Annoying const problem

O

Old Wolf

I have a function that always takes 16 bytes of data and doesn't modify
it:

void func( byte const (*data)[16] );

However, if I try to call it with non-const data, the compiler is
unable to perform the conversion:

static const byte bar1[16] = { 0 };

int foo()
{
byte bar2[16] = { 0 };

func( &bar1 ); /* OK */
func( &bar2 ); /* Error */
}

Is there any work-around to this, other than defining a const and a
nonconst version of func, or passing a pointer to the first element
of data and thereby losing the compile-time length check?
 
C

CBFalconer

Old said:
I have a function that always takes 16 bytes of data and doesn't
modify it:

void func( byte const (*data)[16] );

However, if I try to call it with non-const data, the compiler is
unable to perform the conversion:

static const byte bar1[16] = { 0 };

int foo()
{
byte bar2[16] = { 0 };

func( &bar1 ); /* OK */
func( &bar2 ); /* Error */
}

Is there any work-around to this, other than defining a const and a
nonconst version of func, or passing a pointer to the first element
of data and thereby losing the compile-time length check?

Probably it will be enough to compile with a C compiler. Looks
like you are using C++.
 
R

Richard Tobin

Old Wolf said:
void func( byte const (*data)[16] );

[Presumably byte is typedefed.]
However, if I try to call it with non-const data, the compiler is
unable to perform the conversion:

You'll have to put in an explicit cast:

func( (byte const (*)[16]) &bar2 );

Of course, this loses the type checking, but only for the cases where
you cast it.

-- Richard
 
O

Old Wolf

CBFalconer said:
Old said:
void func( byte const (*data)[16] );
static const byte bar1[16] = { 0 };

int foo()
{
byte bar2[16] = { 0 };

func( &bar1 ); /* OK */
func( &bar2 ); /* Error */
}

Probably it will be enough to compile with a C compiler. Looks
like you are using C++.

Actually I'm not. Thanks for guessing though. What C compiler are
you using that compiles this code without issuing a diagnostic?

typedef unsigned char byte;
void func( byte const (*data)[16] ) {}
int main()
{
byte bar[16] = { 0 };
func( &bar );
}
 
T

Thad Smith

Old said:
I have a function that always takes 16 bytes of data and doesn't modify
it:

void func( byte const (*data)[16] );

However, if I try to call it with non-const data, the compiler is
unable to perform the conversion:

static const byte bar1[16] = { 0 };

int foo()
{
byte bar2[16] = { 0 };

func( &bar1 ); /* OK */
func( &bar2 ); /* Error */
}

Is there any work-around to this, other than defining a const and a
nonconst version of func, or passing a pointer to the first element
of data and thereby losing the compile-time length check?

I think not. The non-const version can, of course, be a wrapper for the
const version.
 
G

Guest

Old said:
CBFalconer said:
Old said:
void func( byte const (*data)[16] );
static const byte bar1[16] = { 0 };

int foo()
{
byte bar2[16] = { 0 };

func( &bar1 ); /* OK */
func( &bar2 ); /* Error */
}

Probably it will be enough to compile with a C compiler. Looks
like you are using C++.

Actually I'm not. Thanks for guessing though. What C compiler are
you using that compiles this code without issuing a diagnostic?

typedef unsigned char byte;
void func( byte const (*data)[16] ) {}
int main()
{
byte bar[16] = { 0 };
func( &bar );
}

The tendra compiler accepts it without a diagnostic. With extra
warnings enabled, it still only warns about an unused variable "data".
Of course, considering gcc, icc and comeau (online) all report an
error, I would not be surprised if it is a bug.
 
R

Richard Heathfield

Old Wolf said:
I have a function that always takes 16 bytes of data and doesn't modify
it:

void func( byte const (*data)[16] );

However, if I try to call it with non-const data, the compiler is
unable to perform the conversion:

static const byte bar1[16] = { 0 };

int foo()
{
byte bar2[16] = { 0 };

func( &bar1 ); /* OK */
func( &bar2 ); /* Error */
}

Please produce the smallest *compilable* program (in the sense that it would
compile if not for your func(&bar2) call) that reproduces the problem.
 
R

Richard Heathfield

Old Wolf said:

typedef unsigned char byte;
void func( byte const (*data)[16] ) {}
int main()
{
byte bar[16] = { 0 };
func( &bar );
}

I hate questions like this, and I'm not going to try to explain it, but
FWIW:

typedef unsigned char byte;
void func( byte (* const data)[16] ) {} /* observe the difference here */
int main()
{
byte bar[16] = { 0 };
func( &bar );
return 0;
}

compiles cleanly (modulo one utterly irrelevant warning) under gcc, using
moderately strict flags (-W -Wall -ansi -pedantic).

So it seems to me that, once more, we are staring at C's recondite handling
of pointers to const data (as opposed to const pointers to data), the logic
of which I understood for about 20 minutes back in 2001, and promptly
forgot again.
 
R

Richard Tobin

Old Wolf said:
See my response to CBF else-thread

Since this thread has not yet included a (natural) language flame, I
would point out that "else-thread" should not mean what you want it to
mean. By analogy with "elsewhere", which means "somewhere else", it
should mean "somethread else" - that is, in a different thread.

-- Richard
 
O

Old Wolf

Richard said:
Old Wolf said:
typedef unsigned char byte;
void func( byte const (*data)[16] ) {}
int main()
{
byte bar[16] = { 0 };
func( &bar );
}

I hate questions like this, and I'm not going to try to explain it, but
FWIW:

typedef unsigned char byte;
void func( byte (* const data)[16] ) {} /* observe the difference here */
int main()
{
byte bar[16] = { 0 };
func( &bar );
return 0;
}

compiles cleanly (modulo one utterly irrelevant warning) under gcc, using
moderately strict flags (-W -Wall -ansi -pedantic).

This is a top-level const, which is only relevant within func,
it does not affect what you can pass to it. So this version does
not allow:

byte const baz[16] = { 0 };
func(&baz);

which was part of my original problem and I should have included
it in the above sample code.
So it seems to me that, once more, we are staring at C's
recondite handling of pointers to const data (as opposed
to const pointers to data), the logic of which I understood
for about 20 minutes back in 2001, and promptly forgot again.

The above code seems to demonstrate that an array of objects,
each of which is const, is somehow different to a const array of
objects, each of which is not const.

If you understood this, then you understood it for 20 minutes
more than I did :)

FWIW the code compiles successfully in C++.
 
C

Chris Torek

Old Wolf said:
FWIW the code compiles successfully in C++.

Sadly, the "const" rules in C are just broken. (The C++ rules
work. They do, however, pretty much need a lot of the rest of the
C++ machinery -- such as function overloading -- to work consistently.
C could have used the C++ rules, but the result would still be less
secure than the C++ rules, due to functions like strchr() removing
"const" qualifiers [in C].)

My preferred solution is to omit "const" as much as possible in C
code, but I recognize that not everyone favors this approach. :)

I also wish that, in lieu of the C folks using "correct" rules
a la C++, they had simply made "const" a storage modifier rather
than a "type qualifier". In this case, "const" would have meant
"put this object into read-only memory if possible", but would have
had no effect at all on its type. Many argue that this would lose
some type-safety, but given, e.g.:

const char *qual;
...
char *unqual = strchr(unqual, *unqual);

we already get C code that quietly removes "const", so I think this
"some" type-safety is "very little" type-safety, and not worth its
cost.
 
J

James Antill

Gah. This call is, of course, supposed to read:

char *unqual = strchr(qual, *qual);

strchr()/strrchr() is a big wart (but then so is all of string.h, IMO).

However it is possible/easy/better to have a string API that doesn't
return a pointer to offsets within itself (and if you insist on
using string.h then strspn/strcspn can easily be used).
And non-string APIs tend to not even consider design decisions like that.
So, while const does have it's problems (see earlier in this thread),
using a (const Foo *foo) parameter in a function provides great
documentation and is worth using.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top