f



Incompatible pointer types with GCC

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
0
August
12/16/2016 10:41:03 AM
comp.lang.c 30656 articles. 5 followers. spinoza1111 (3246) is leader. Post Follow

7 Replies
713 Views

Similar Articles

[PageSpeed] 10

On 16/12/2016 10:41, August Karlstrom wrote:
> 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?

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
0
BartC
12/16/2016 11:06:01 AM
August Karlstrom <fusionfile@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.
0
Ben
12/16/2016 5:07:43 PM
On 2016-12-16 18:07, Ben Bacarisse wrote:
> August Karlstrom <fusionfile@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
0
August
12/16/2016 10:02:38 PM
August Karlstrom <fusionfile@gmail.com> writes:

> On 2016-12-16 18:07, Ben Bacarisse wrote:
>> August Karlstrom <fusionfile@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.
0
Ben
12/17/2016 12:48:09 AM
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 <fusionfile@gmail.com> writes:
> > The [] might confuse some people.  This is simply
> >
> >         void P(const Row *A)
>=20
> I prefer to use brackets when a sequence is expected, it provides more=20
> semantic information.
>=20
> >> test.c:3:6: note: expected =E2=80=98const int (*)[10]=E2=80=99 but arg=
ument is of type
> >> =E2=80=98int (*)[10]=E2=80=99
> >>  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 i=
f
> > by assignment", and in an assignment the pointed-to type on the left ca=
n
> > 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).
>=20
> 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.=20

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.=20

Martin
0
martin
12/18/2016 4:06:35 PM
martin.uecker@med.uni-goettingen.de writes:

> 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 <fusionfile@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

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.
0
Ben
12/18/2016 8:11:26 PM
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.
 
0
supercat
12/18/2016 10:43:22 PM
Reply: