2D const array nested functions warning question

A

Andres Meyer

Hello,

I am trying to compile the very simple program below and am getting this
error:

$ gcc -Wall -ansi -o test test.c
test.c: In function âmainâ:
test.c:17: warning: passing argument 1 of âf2â from incompatible pointer
type

$ gcc --version
gcc (GCC) 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)


Could someone tell me what trivial thing I am doing wrong? I am just
trying to make the int values of the array not modifiable in both
functions. I do not get this warning without the const modifiers.

Cheers,
Andres


test.c:

#include <stdio.h>

void f1(const int i[][2])
{
printf("%d\n", i[0][0]);
}

void f2(const int j[][2])
{
f1(j);
}

int main()
{
int m[2][2];
m[0][0] = 5;
f2(m);
return 0;
}
 
M

Micah Cowan

Andres said:
Could someone tell me what trivial thing I am doing wrong? I am just
trying to make the int values of the array not modifiable in both
functions. I do not get this warning without the const modifiers.

void f1(const int i[][2])

As a parameter, i is equivalent to:
const int (*i)[2]
a pointer to an array of 2 const int.
int m[2][2]; ....
f2(m);
This passes an int (*i)[2], or pointer to an array of 2 int.

The problem you're having stems from the fact that pointers to FOO
aren't compatible with pointers to BAR, where BAR is declared the same
as FOO, except there are extra const specifiers buried in there.

C makes a _special_ exception for assigning pointers to FOO to pointers
of const FOO. Unfortunately, what you have here is a pointer to an
_array_ of const FOO. If the "const" isn't right after "pointer", it's
not allowed. What you'd want is a "pointer to a const array of int"

What sucks about this, of course, is that there really would be no
semantic difference between "pointer to an array of const int", and
"pointer to a const array of int"; but there isn't a way to declare the
latter, while the former still technically fails to meet the special
assignment exception. One might think you could do:

typedef int ary[2]; /* ary is array 2 of int */
const ary *foo; /* foo is const array 2 of int */

But you can't: C still defines that (under the definition for type
qualifiers) as "an array 2 of const int". :(

I'm actually not sure how you could manage this without a cast (which
will give undefined behavior if you use the result, though it's
extremely likely to work "as expected" on any actual implementation).
Your best bet may be to use it without the const qualifiers.

I'm hoping someone will jump in now with a clever workaround.
 
A

Andrey Tarasevich

Andres said:
...
Could someone tell me what trivial thing I am doing wrong?
> ...

It is just one of the quirks of the language. Normally one'd expect that
a value of type 'T*' can be implicitly converted to type 'const T*'.
This is true most of the time, but unfortunately when 'T' is an array
type the conversion is not allowed

typedef int T[2];
T* p = 0;
const T* c = p; // <- ERROR

That's just an unpleasant side-effect of the way the const-correctness
rules are formulated in C. And this is exactly what happens in your
code, if you analyze it carefully.

C++ went with a more elaborate specification, which makes more sense and
doesn't suffer from this issue, but C continues to stick with that old
strange one for some reason.
 
D

David Thompson

Andres Meyer wrote:
void f1(const int i[][2])

As a parameter, i is equivalent to:
const int (*i)[2]
a pointer to an array of 2 const int.
int m[2][2]; ...
f2(m);
This passes an int (*i)[2], or pointer to an array of 2 int.

The problem you're having stems from the fact that pointers to FOO
aren't compatible with pointers to BAR, where BAR is declared the same
as FOO, except there are extra const specifiers buried in there.

C makes a _special_ exception for assigning pointers to FOO to pointers
of const FOO. Unfortunately, what you have here is a pointer to an
_array_ of const FOO. If the "const" isn't right after "pointer", it's
not allowed. What you'd want is a "pointer to a const array of int"
Agree so far.

I'm actually not sure how you could manage this without a cast (which
will give undefined behavior if you use the result, though it's
extremely likely to work "as expected" on any actual implementation).

Yes you need the cast, but no it doesn't produce UB.

The qualified type has the same alignment requirement (6.2.5p25) and
the cast of a valid pointer value (as here) produces a valid and equal
one (6.3.2.3p2,7) and derefencing it gives a valid (though qualified)
lvalue which can correctly be used to read the object (6.5p7).

Attempting to deconstify and write an object _defined_ const is UB,
but that's not the situation here.
Your best bet may be to use it without the const qualifiers.
That is indeed easier.

- formerly david.thompson1 || achar(64) || worldnet.att.net
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top