Warning about constness (I think)

S

s0suk3

gcc is displaying a warning that confuses me. The warning goes away if
I cast the expression in the return statement in f() to a const-
qualified type (in this case, to const char**):

#include <stdio.h>

typedef struct A
{
char** argv;
} A;

const char** f(const A* a)
{
return (char**) a->argv + 1;
}

int main(int argc, char* argv[])
{
A a = {argv};
printf("%s\n", *f(&a));
return 0;
}

$ gcc warning.c
warning.c: In function 'f':
warning.c:10: warning: return from incompatible pointer type

But the warning suggests that the problem is in the return type rather
than in the cast (which seems strange, since a particular type ``T''
can always be converted to ``const T'').

What's even stranger is that there are no warnings for the following:

#include <stdio.h>

typedef struct A
{
char* argv0;
} A;

const char* f(const A* a)
{
return (char*) a->argv0 + 1;
}

int main(int argc, char* argv[])
{
A a = {argv[0]};
printf("%s\n", f(&a));
return 0;
}

Essentially the only difference is that this deals with char* rather
than char**, which doesn't explain why there's no warning anymore.

I think the confusion is compounded by the fact that there's a const-
qualified instance of a structure that has a non-const-qualified
member.

So what's the warning all about?

Sebastian
 
G

gw7rib

gcc is displaying a warning that confuses me. The warning goes away if
I cast the expression in the return statement in f() to a const-
qualified type (in this case, to const char**):

#include <stdio.h>

typedef struct A
{
    char** argv;

} A;

const char** f(const A* a)
{
    return (char**) a->argv + 1;

}

int main(int argc, char* argv[])
{
    A a = {argv};
    printf("%s\n", *f(&a));
    return 0;

}

$ gcc warning.c
warning.c: In function 'f':
warning.c:10: warning: return from incompatible pointer type

But the warning suggests that the problem is in the return type rather
than in the cast (which seems strange, since a particular type ``T''
can always be converted to ``const T'').

I think you have a slightly dressed up version of FAQ 11.10.
 
B

Ben Bacarisse

gcc is displaying a warning that confuses me. The warning goes away if
I cast the expression in the return statement in f() to a const-
qualified type (in this case, to const char**):

#include <stdio.h>

typedef struct A
{
char** argv;
} A;

const char** f(const A* a)
{
return (char**) a->argv + 1;
}

int main(int argc, char* argv[])
{
A a = {argv};
printf("%s\n", *f(&a));
return 0;
}

$ gcc warning.c
warning.c: In function 'f':
warning.c:10: warning: return from incompatible pointer type

The warning says it all. The two types are not compatible. You
either have to cast or change one or other type.

The fact is that const can be added only "near" the pointer, not at
the outer level. This is a very non-technical description but I excuse
it by the fact that I have written at least two detailed explanations
before on this topic. You might be able to find one of them.
But the warning suggests that the problem is in the return type rather
than in the cast (which seems strange, since a particular type ``T''
can always be converted to ``const T'').

Converted is a little vague. You can always convert between types
with varying degrees of success, but I think you mean you can (without
a cast) always assign something of type T to a variable of type const
T. Assignment is important because function return and parameter
passing are defined in terms of assignment.

Now the trouble is that when "T" is "char **" the type "const T" is
"char **const" and not "const char **". It might help to remember
that "const T" and "T const" are the same type.
What's even stranger is that there are no warnings for the
following:

Yes, it works with one level of pointer. See the description of
assignment and type compatibility to see the real wording.

So what's the warning all about?

Pretty much exactly what is says. A slightly more technical warning
would have said: "return type is not the same as the function type and
can not be converted to the same type as if by assignment" but I
prefer the shorted form.
 
B

Ben Bacarisse

I think you have a slightly dressed up version of FAQ 11.10.

Darn. A much more succinct reply. The FAQ should probably point out
that function return values work the same way but, yes, that pretty
much overs it.
 
C

CBFalconer

gcc is displaying a warning that confuses me. The warning goes
away if I cast the expression in the return statement in f() to
a const-qualified type (in this case, to const char**):

#include <stdio.h>

typedef struct A
{
char** argv;
} A;

const char** f(const A* a)
{
return (char**) a->argv + 1;
} .... snip ...

$ gcc warning.c
warning.c: In function 'f':
warning.c:10: warning: return from incompatible pointer type

a is of type A*, which is a pointer to a 'struct A'. thus a->argv
is of type char**. If it points to a non-empty array of char*,
adding one to it also points to a char*. The return type is const
char**. These are not the same, thus an error. Take the const out
of the function type.
 
B

Ben Bacarisse

CBFalconer said:
a is of type A*,

Nit: a is of type const A*
which is a pointer to a 'struct A'. thus a->argv
is of type char**.

Nit on a nit: which makes a->argv of type char **const.
If it points to a non-empty array of char*,
adding one to it also points to a char*. The return type is const
char**. These are not the same, thus an error.

It is not as simple as that. It is very common to write an expression
in a return statement whose type is not the same as that of the result
of the function. In fact, the OP included an example of exactly that
later on.
 
O

Old Wolf

int main(int argc, char* argv[])
{
    A a = {argv};

Minor nit: this isn't legal in C89, which
requires that the expressions in a brace-
enclosed list be constant expressions.

(Some compilers do allow it and it is annoying
when you port your code to a compiler that doesn't!)
 
C

CBFalconer

Old said:
int main(int argc, char* argv[])
{
A a = {argv};

Minor nit: this isn't legal in C89, which requires that the
expressions in a brace-enclosed list be constant expressions.

(Some compilers do allow it and it is annoying
when you port your code to a compiler that doesn't!)

I would think the annoying thing is the compiler that allows it.
 

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,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top