Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Incompatible pointer types with GCC

121 views
Skip to first unread message

August Karlstrom

unread,
Dec 16, 2016, 5:41:09 AM12/16/16
to
My question is whether this is a valid ANSI C (C89) program or not:

typedef int Row[10];

void P(const Row A[])
{
}


int main(void)
{
Row A[10];

P(A);
return 0;
}

It compiles cleanly with Clang 3.5.0 and the options -pedantic -std=c89
-Wall.

GCC 4.9.2, however, is not happy:

$ gcc -c -o test.o -g -pedantic -std=c89 -Wall test.c
test.c: In function ‘main’:
test.c:12:4: warning: passing argument 1 of ‘P’ from incompatible
pointer type
P(A);
^
test.c:3:6: note: expected ‘const int (*)[10]’ but argument is of type
‘int (*)[10]’
void P(const Row A[])
^

Any clues?


Regards,
August

BartC

unread,
Dec 16, 2016, 6:06:12 AM12/16/16
to
I get:

c.c:16:9: warning: pointers to arrays with different qualifiers are
incompatible in ISO C [-Wpedantic]
P(A);
^

I suspect that, because of the typedef 'Row', the 'const' doesn't apply
to the bit that you think it does. Try dumping 'const' for now and add
it later when the program works.

Or remove the typedef which I think causes problems with arrays.

--
Bartc

Ben Bacarisse

unread,
Dec 16, 2016, 12:07:51 PM12/16/16
to
August Karlstrom <fusio...@gmail.com> writes:

> My question is whether this is a valid ANSI C (C89) program or not:
>
> typedef int Row[10];
>
> void P(const Row A[])

The [] might confuse some people. This is simply

void P(const Row *A)
> {
> }
>
> int main(void)
> {
> Row A[10];
>
> P(A);
> return 0;
> }
>
> It compiles cleanly with Clang 3.5.0 and the options -pedantic
> -std=c89 -Wall.
>
> GCC 4.9.2, however, is not happy:
>
> $ gcc -c -o test.o -g -pedantic -std=c89 -Wall test.c
> test.c: In function ‘main’:
> test.c:12:4: warning: passing argument 1 of ‘P’ from incompatible
> pointer type
> P(A);
> ^
> test.c:3:6: note: expected ‘const int (*)[10]’ but argument is of type
> ‘int (*)[10]’
> void P(const Row A[])
> ^
>
> Any clues?

I think gcc is right to complain.

Whilst the types are not compatible, that's not really the problem here.
For example, you can pass an int * to a function that takes const int *
and those two types are not compatible. Argument passing is done "as if
by assignment", and in an assignment the pointed-to type on the left can
have extra qualifiers. But here, the const qualifies the element type,
not the pointed-to type, which is an array type. (C has not qualified
array types at all).

The call is safe, of course, but C chose to use a simple rule rather
than trying to identify only those calls (and assignments) that are not
safe. C++ has a more comprehensive rule.

Cases like this (and passing to a const T ** parameter) are some of the
rare times when you really need a cast.

--
Ben.

August Karlstrom

unread,
Dec 16, 2016, 5:02:46 PM12/16/16
to
On 2016-12-16 18:07, Ben Bacarisse wrote:
> August Karlstrom <fusio...@gmail.com> writes:
> The [] might confuse some people. This is simply
>
> void P(const Row *A)

I prefer to use brackets when a sequence is expected, it provides more
semantic information.

>> test.c:3:6: note: expected ‘const int (*)[10]’ but argument is of type
>> ‘int (*)[10]’
>> void P(const Row A[])
>> ^
>
> I think gcc is right to complain.
>
> Whilst the types are not compatible, that's not really the problem here.
> For example, you can pass an int * to a function that takes const int *
> and those two types are not compatible. Argument passing is done "as if
> by assignment", and in an assignment the pointed-to type on the left can
> have extra qualifiers. But here, the const qualifies the element type,
> not the pointed-to type, which is an array type. (C has not qualified
> array types at all).

That's counter-intuitive. I thought const applied to Row.

> The call is safe, of course, but C chose to use a simple rule rather
> than trying to identify only those calls (and assignments) that are not
> safe. C++ has a more comprehensive rule.
>
> Cases like this (and passing to a const T ** parameter) are some of the
> rare times when you really need a cast.

OK, thanks for the clarification.


-- August

Ben Bacarisse

unread,
Dec 16, 2016, 7:48:17 PM12/16/16
to
August Karlstrom <fusio...@gmail.com> writes:

> On 2016-12-16 18:07, Ben Bacarisse wrote:
>> August Karlstrom <fusio...@gmail.com> writes:
>> The [] might confuse some people. This is simply
>>
>> void P(const Row *A)
>
> I prefer to use brackets when a sequence is expected, it provides more
> semantic information.

Yes, that's a reasonable thing to do, but I thought it best to clarify
(for others) that A is a plain old pointer.

>>> test.c:3:6: note: expected ‘const int (*)[10]’ but argument is of type
>>> ‘int (*)[10]’
>>> void P(const Row A[])
>>> ^
>>
>> I think gcc is right to complain.
>>
>> Whilst the types are not compatible, that's not really the problem here.
>> For example, you can pass an int * to a function that takes const int *
>> and those two types are not compatible. Argument passing is done "as if
>> by assignment", and in an assignment the pointed-to type on the left can
>> have extra qualifiers. But here, the const qualifies the element type,
>> not the pointed-to type, which is an array type. (C has not qualified
>> array types at all).
>
> That's counter-intuitive. I thought const applied to Row.

Well... in some way it does, it's just that qualifying an array type
means qualifying the element type.

>> The call is safe, of course, but C chose to use a simple rule rather
>> than trying to identify only those calls (and assignments) that are not
>> safe. C++ has a more comprehensive rule.
>>
>> Cases like this (and passing to a const T ** parameter) are some of the
>> rare times when you really need a cast.
>
> OK, thanks for the clarification.

Hang on for a bit, just in case someone decides I got it all wrong!

--
Ben.

martin...@med.uni-goettingen.de

unread,
Dec 18, 2016, 11:06:43 AM12/18/16
to
On Friday, December 16, 2016 at 11:02:46 PM UTC+1, August Karlstrom wrote:
> On 2016-12-16 18:07, Ben Bacarisse wrote:
> > August Karlstrom <fusio...@gmail.com> writes:
> > The [] might confuse some people. This is simply
> >
> > void P(const Row *A)
>
> I prefer to use brackets when a sequence is expected, it provides more
> semantic information.
>
> >> test.c:3:6: note: expected ‘const int (*)[10]’ but argument is of type
> >> ‘int (*)[10]’
> >> void P(const Row A[])
> >> ^
> >
> > I think gcc is right to complain.
> >
> > Whilst the types are not compatible, that's not really the problem here.
> > For example, you can pass an int * to a function that takes const int *
> > and those two types are not compatible. Argument passing is done "as if
> > by assignment", and in an assignment the pointed-to type on the left can
> > have extra qualifiers. But here, the const qualifies the element type,
> > not the pointed-to type, which is an array type. (C has not qualified
> > array types at all).
>
> That's counter-intuitive. I thought const applied to Row.

Yes, I hope (and it seems) that this gets fixed in the next revision
of the C standard. Arrays should behave like structs with respect
to const but currently they don't.

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1923.htm


Without '-pedantic' gcc will accept this, so I recommend to use
this non-standard extension instead of adding casts which
break type safety.

Martin

Ben Bacarisse

unread,
Dec 18, 2016, 3:11:38 PM12/18/16
to
Interesting. Thanks for posting that.

> Without '-pedantic' gcc will accept this, so I recommend to use
> this non-standard extension instead of adding casts which
> break type safety.

Casts can break type safety, but in this case that cast is really just
permitting a safe operation currently ruled out by the language. It may
be that the value of -pedantic outweighs the concerns about adding what
is, after all, a safe cast.

--
Ben.

supe...@casperkitty.com

unread,
Dec 18, 2016, 5:43:30 PM12/18/16
to
On Sunday, December 18, 2016 at 2:11:38 PM UTC-6, Ben Bacarisse wrote:
> > Yes, I hope (and it seems) that this gets fixed in the next revision
> > of the C standard. Arrays should behave like structs with respect
> > to const but currently they don't.
> >
> > http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1923.htm
>
> Interesting. Thanks for posting that.
>
> > Without '-pedantic' gcc will accept this, so I recommend to use
> > this non-standard extension instead of adding casts which
> > break type safety.
>
> Casts can break type safety, but in this case that cast is really just
> permitting a safe operation currently ruled out by the language. It may
> be that the value of -pedantic outweighs the concerns about adding what
> is, after all, a safe cast.

The problem, fundamentally, is that rather that rather than allowing use
of parentheses to distinguish between "int (const foo[4][4])" and
"(int const)foo[4][5]", someone decided that qualifiers should be applied
to the variable by putting them inside the subscript expression--something
which totally fails with array type specifiers that don't include subscript
expressions, and doesn't really make sense anyhow.

Tim Rentsch

unread,
Dec 29, 2016, 4:33:43 PM12/29/16
to
supe...@casperkitty.com writes:

> On Sunday, December 18, 2016 at 2:11:38 PM UTC-6, Ben Bacarisse wrote:
>>> Yes, I hope (and it seems) that this gets fixed in the next revision
>>> of the C standard. Arrays should behave like structs with respect
>>> to const but currently they don't.
>>>
>>> http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1923.htm
>>
>> Interesting. Thanks for posting that.
>>
>>> Without '-pedantic' gcc will accept this, so I recommend to use
>>> this non-standard extension instead of adding casts which
>>> break type safety.
>>
>> Casts can break type safety, but in this case that cast is really just
>> permitting a safe operation currently ruled out by the language. It may
>> be that the value of -pedantic outweighs the concerns about adding what
>> is, after all, a safe cast.
>
> The problem, fundamentally, is that rather that rather than allowing use
> of parentheses to distinguish between "int (const foo[4][4])" and
> "(int const)foo[4][5]", someone decided that qualifiers should be applied
> to the variable by putting them inside the subscript expression--[...]

The problem, fundamentally, is that you are clueless. That
has nothing to do with the issue being addressed here.
0 new messages