Re: Q about passing data as a const array
- From: Keith Thompson <kst-u@xxxxxxx>
- Date: Thu, 15 Jan 2009 09:41:17 -0800
cri@xxxxxxxx (Richard Harter) writes:
On Wed, 14 Jan 2009 00:31:50 -0800, Keith Thompson
<kst-u@xxxxxxx> wrote:
cri@xxxxxxxx (Richard Harter) writes:
Here is a simple question. I have data that I want to pass to a
function; I don't want the function to scribble on it. Does
something like this work?
void func(const size_t len,const char data[]);
...
char * data;
size_t len;
/* code creating data and giving it content */
...
func(len,data);
It should. The const on the len parameter is superfluous; it
prevents func from modifying its own local copy, but it can't
modify the argument anyway. As for "const char data[]", that's
exactly equivalent to "const char *data", which means that func
can't modify the stuff that the pointer points to.
Thanks; I thought that was how it would be interepreted, but I
thought I would check. Now take the next step:
struct mydata {
size_t len;
char * data;
};
void func(const struct mydata foo);
...
struct mydata bar;
...
func(bar);
Now the question is, does the const qualifier forbid altering the
contents of foo.data? What is the actual rule here?
Yes, the const qualifier forbids func() from altering the contents of
foo.data. It doesn't forbid altering the contents of bar.data; that's
forbidden by the fact that C passes arguments by value. Applying a
const qualifier directly to an argument declaration, as you've done
here, is not very useful; all it does is prevent the function from
modifying the value of its own local copy of the argument value.
Applying const to a pointer parameter can be quite useful, as it
prevents modification of what the pointer points to (e.g., "const char
*param", which is useful, as opposed to "char *const param", which is
much less useful).
But I don't think you asked the question that you meant to ask. The
"contents of foo.data" are a pointer value; func() cannot alter that
pointer value. But I think what you're concerned about is the
contents of what foo.data points to. And the answer is no, applying
"const" to the declaration of the parameter "foo" doesn't prevent
modifying what foo.data points to. To do that, you'd have to declare
it as "const char *data;" -- but that requires modifying the type
declaration, which affects all uses of the type.
I suppose you could declare two different structures:
struct var_mydata {
size_t len;
char *data;
};
struct const_mydata {
size_t len;
const char *data;
};
and use some kind of type-punning to choose, for each particular
usage, whether you want to allow modification of the pointed-to data
or not. But that's ugly, and I'm not sure it's even guaranteed to
work.
Or you could pass len and data as separate arguments, which lets you
declare data as "const char *data", but that loses the advantage of
putting them together into a struct.
[...]Of course func can always cast its argument to a non-const type,
or do any of several other nasty things, but if it doesn't cheat
you should be ok.
What it comes down to is that there is no way to create immutable
data that is guaranteed to survive being passed through a
function a call. The implication is that you can't rigorously do
message passing by passing references; the only safe thing to do
in C is to copy data to the message.
I think there's a better approach. Make your "mydata" an opaque type,
and define all allowed operations on it in the same module where you
define the type itself. Code that uses your module will never modify
the pointed-to data unless you let it do so, simply because you
haven't written the code that modifies it. You'll still have to make
sure the code in your module doesn't incorrectly modify anything it's
not supposed to, but that issue is limited to a single, probably
fairly small, source file. See type FILE in <stdio.h> for an example
of this.
No matter what you do, a malicious programmer could always read your
source code, figure out how "mydata" is defined, and do whatever
pointer casting is necessary to clobber your data. There's no way to
guard against that, at least not within a single program (if there
were, we probably wouldn't have malware). If you want to avoid even
that possibility, you best bet is to run all the code that manages
"mydata" on a separate computer, with communication via a network --
and then unplug the network cable and fill the ethernet port with
epoxy. And unplug the power cord. And erase the hard drive. And go
back in time and prevent the invention of the computer. And ...
--
Keith Thompson (The_Other_Keith) kst-u@xxxxxxx <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
.
- Follow-Ups:
- Re: Q about passing data as a const array
- From: Richard Harter
- Re: Q about passing data as a const array
- References:
- Q about passing data as a const array
- From: Richard Harter
- Re: Q about passing data as a const array
- From: Keith Thompson
- Re: Q about passing data as a const array
- From: Richard Harter
- Q about passing data as a const array
- Prev by Date: Re: C vs. C++
- Next by Date: Re: MACRO QUERY-3
- Previous by thread: Re: Q about passing data as a const array
- Next by thread: Re: Q about passing data as a const array
- Index(es):
Relevant Pages
|