const array of const pointers as a parameter

S

Spoon

Hello,

I don't understand why gcc barks at me in this situation:

$ cat foo.c
extern void func(const int * const list[], int nent);

int main(void)
{
int *p[5];
func(p, 5);
return 0;
}

$ gcc -Wall -std=c89 -c foo.c
foo.c: In function `main':
foo.c:6: warning: passing arg 1 of `func' from incompatible pointer type

AFAIU, func promises not to change the values pointed to by the pointers
in the array (i.e. *list[2] = 666 is illegal) AND not to change the
pointers themselves (i.e. list[2] = NULL is also illegal).

I don't understand what the compiler dislikes about p.

Could someone enlighten me?
 
D

Darko

Hm. I myself too had trouble with consts pretty much the same way you
do now. As far as I can recall, multiple consts in the same expression
are not allowed by ANSI. However, lots of things seem not to be allowed
by ANSI and yet are quite normal in practice.

Anyway, my humble opinion is that you should try adding another const
at the and of your "list" expression, like in: const int * const * list
const. That way you declare list to be constant, too, which is true
because what you've got down there is a static array, which is actually
a constant pointer to another pointer.

I would try it myself but I don't have Linux here at work.

Bye,

Darko
 
A

arne

Spoon said:
Hello,

I don't understand why gcc barks at me in this situation:

$ cat foo.c
extern void func(const int * const list[], int nent);

int main(void)
{
int *p[5];
func(p, 5);
return 0;
}

$ gcc -Wall -std=c89 -c foo.c
foo.c: In function `main':
foo.c:6: warning: passing arg 1 of `func' from incompatible pointer type

AFAIU, func promises not to change the values pointed to by the pointers
in the array (i.e. *list[2] = 666 is illegal) AND not to change the
pointers themselves (i.e. list[2] = NULL is also illegal).

I don't understand what the compiler dislikes about p.

Could someone enlighten me?

What about changing

int *p[5];

to

const int *p[5]; ?


The function expects an array of const pointers to const ints, but you
pass an array of pointers to ints.
 
A

Andrey Tarasevich

Spoon said:
Hello,

I don't understand why gcc barks at me in this situation:

$ cat foo.c
extern void func(const int * const list[], int nent);

int main(void)
{
int *p[5];
func(p, 5);
return 0;
}

$ gcc -Wall -std=c89 -c foo.c
foo.c: In function `main':
foo.c:6: warning: passing arg 1 of `func' from incompatible pointer type

AFAIU, func promises not to change the values pointed to by the pointers
in the array (i.e. *list[2] = 666 is illegal) AND not to change the
pointers themselves (i.e. list[2] = NULL is also illegal).

I don't understand what the compiler dislikes about p.
...

The function parameter declaration is equivalent to 'const int* const* list'.
The type of actual argument (array 'p') decays to 'int**'. In other words, you
are trying to initialize an object of type 'const int* const*' with a value of
type 'int**'. This is not allowed by const-correctness rules of C language. The
culprit is the first 'const' from the left. C language allows you to "add" a
'const' at the first level of indirection, but not at any deeper level of
indirection. I.e. it is OK to convert 'int**' to 'int* const*', but it is not OK
to convert it to either 'const int**' or 'const int* const*'.

The rationale behind this is described in the following C++ (sic) FAQ entry

http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17

This is a C++ FAQ entry, but it does explain the issue very well. (There's also
a similar example in C99 standard.) However, C++ language adopted a more
elaborate behavior in this case and, as a result, C++ actually _allows_ the
'int**' to 'const int* const*' conversion (still disallowing the conversion to
'const int**'). C language decided to stay with a more primitive/simplified
specification, meaning that 'int**' to 'const int* const*' conversion is
outlawed in C, even though it's harmless from the const-correctness point of view.
 
A

A. Bolmarcich

Hello,

I don't understand why gcc barks at me in this situation:

$ cat foo.c
extern void func(const int * const list[], int nent);

int main(void)
{
int *p[5];
func(p, 5);
return 0;
}

$ gcc -Wall -std=c89 -c foo.c
foo.c: In function `main':
foo.c:6: warning: passing arg 1 of `func' from incompatible pointer type

AFAIU, func promises not to change the values pointed to by the pointers
in the array (i.e. *list[2] = 666 is illegal) AND not to change the
pointers themselves (i.e. list[2] = NULL is also illegal).

I don't understand what the compiler dislikes about p.

Could someone enlighten me?

The assignment constraint in the C89 specification being used in this
case is

both operands are pointers to qualified or unqualified types verisons
of compatible types, and the type pointed to by the left has all the
qualifiers as the type pointed to by the right

Also, according th the C89 specification

For two qualified types to be compatible, both shall have the identical
qualified versions of a compatible type

The argument type is pointerTo-pointerTo-int and the parameter type is
pointerTo-pointerTo-const-int. According to the C89 specification
a pointerTo-int is not compatible with pointerTo-const-int because they
are not identically qualified.

The assignment constraint allows the parameter to have additional
"top-level" pointer qualifiers that the argument does not have. This
allows a (* int) argument to be assigned to a (const * int) parameter.
However, that constraint does not apply to "inner-level" pointers which
need to be identically qualified.
 
J

John Bode

Spoon said:
Hello,

I don't understand why gcc barks at me in this situation:

$ cat foo.c
extern void func(const int * const list[], int nent);

int main(void)
{
int *p[5];

This is not an array of constant pointers. That's why you're getting
barked at.

If you declare it as

int const *p[5];

the code should compile (it does for me, anyway). Whether that's what
you really *want* to do is an open question (I suspect it isn't).
func(p, 5);
return 0;
}

$ gcc -Wall -std=c89 -c foo.c
foo.c: In function `main':
foo.c:6: warning: passing arg 1 of `func' from incompatible pointer type

AFAIU, func promises not to change the values pointed to by the pointers
in the array (i.e. *list[2] = 666 is illegal) AND not to change the
pointers themselves (i.e. list[2] = NULL is also illegal).

I don't understand what the compiler dislikes about p.

Could someone enlighten me?
 
L

lawrence.jones

Andrey Tarasevich said:
This is a C++ FAQ entry, but it does explain the issue very well. (There's also
a similar example in C99 standard.) However, C++ language adopted a more
elaborate behavior in this case and, as a result, C++ actually _allows_ the
'int**' to 'const int* const*' conversion (still disallowing the conversion to
'const int**'). C language decided to stay with a more primitive/simplified
specification, meaning that 'int**' to 'const int* const*' conversion is
outlawed in C, even though it's harmless from the const-correctness point of view.

In particular, the original C rules were developed before the C++ rules
had been worked out. Once they were, the way C++ describes the common
language is sufficiently different from the way C describes it that the
rules could not just be lifted verbatim but would have to be rewritten
(in particular, I seem to recall some unrelated handwaving in the C++
standard that happens to make arrays work out right that does not exist
in the C standard). Also, C added the restrict type qualifier, which
complicates the rules since it does not work the same way as const and
volatile do. So far as I know, no one has worked out the rules with
restrict included.

-Larry Jones

Hey Doc, for 10 bucks I'll make sure you see those kids in the
waiting room again real soon! -- Calvin
 

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,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top