Vexing GCC warnings: "assignment discards qualifiers from pointertarget type"

C

Charlie Zender

Hi,

I am unable to compile a large body of code with extremely pedantic
compile time checks activate, so that warnings cause errors.
With GCC 3.3.1, I do this with

gcc -std=c99 -pedantic -Wall -Wunused -Werror -W -Wmissing-prototypes
-Wconversion -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align
-Wwrite-strings -c -o foo.o foo.c

(This is basically what GSL recommendsd for scientific codes.)

The problem is that I have a lot of code that generates these warnings:

foo.c:258: warning: "assignment discards qualifiers from pointer target
type"

This warning occurs when I try to return string literals (e.g., error
messages) to a calling function. Currently, I use code like

char * err_sng(const int err_nbr){
switch(err_nbr){
case 0: return "Message 0";
case 1: return "Message 1";
}
}

1. Say you have a function whose purpose is to return a constant
string literal (e.g., an error message) to a calling function.
How would you write this type of function so as not to generate
"assignment discards qualifiers" warnings?

Note that these warnings disappear if I prototype the function as

const char * err_sng(int err_nbr);

Is that legal? I suspect that qualifying a return value is a GNUism
and am not sure if there is a preferred method that avoids this
dubious prototype.

Any help appreciated,
Charlie
 
P

Peter Pichler

Charlie Zender said:
The problem is that I have a lot of code that generates these warnings:

foo.c:258: warning: "assignment discards qualifiers from pointer target
type"

This warning occurs when I try to return string literals (e.g., error
messages) to a calling function. Currently, I use code like

char * err_sng(const int err_nbr){
switch(err_nbr){
case 0: return "Message 0";
case 1: return "Message 1";
}
}

1. Say you have a function whose purpose is to return a constant
string literal (e.g., an error message) to a calling function.
How would you write this type of function so as not to generate
"assignment discards qualifiers" warnings?

return const char * instead of char *.
Note that these warnings disappear if I prototype the function as

const char * err_sng(int err_nbr);

See? I told you!
Is that legal? I suspect that qualifying a return value is a GNUism
and am not sure if there is a preferred method that avoids this
dubious prototype.

Dubious? Where have you been the last 15 years?

Seriously, string literals in C have a type char[], not const char[] as one
would expect when trying to modify them causes a UB. GCC probably realizes
that and tries to prevent you from doing something stupid by warning about
returning a string literal as char * without const.

Hope this helps,

Peter
 
C

Charlie Zender

Thanks.
Dubious? Where have you been the last 15 years?

My experience has been that some compilers warned about qualifiers on
return values in function prototypes. This was some time ago, though,
and they may have been C++ compilers, I can't remember.
Anyway, if it's legal, then great, it fixes the problem perfectly.
Seriously, string literals in C have a type char[], not const char[] as one
would expect when trying to modify them causes a UB. GCC probably realizes
that and tries to prevent you from doing something stupid by warning about
returning a string literal as char * without const.

Yes, agreed.
Hope this helps,

It does. I've got another question to post soon...

Charlie
 
M

Martin Ambuhl

Charlie said:
Hi,

I am unable to compile a large body of code with extremely pedantic
compile time checks activate, so that warnings cause errors.
With GCC 3.3.1, I do this with

gcc -std=c99 -pedantic -Wall -Wunused -Werror -W -Wmissing-prototypes
-Wconversion -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align
-Wwrite-strings -c -o foo.o foo.c

(This is basically what GSL recommendsd for scientific codes.)

The problem is that I have a lot of code that generates these warnings:

foo.c:258: warning: "assignment discards qualifiers from pointer target
type"

This warning occurs when I try to return string literals (e.g., error
messages) to a calling function. Currently, I use code like

char * err_sng(const int err_nbr){
switch(err_nbr){
case 0: return "Message 0";
case 1: return "Message 1";
}
}

#include <stdio.h>
const char *err_sng(const int err_nbr)
{
switch (err_nbr) {
case 0:
return "Message 0";
case 1:
return "Message 1";
default:
return "Huh?";
}
}

int main(void)
{
fprintf(stderr, "%s\n", err_sng(0));
fprintf(stderr, "%s\n", err_sng(1));
fprintf(stderr, "%s\n", err_sng(2));
return 0;
}


[output]


Message 0
Message 1
Huh?


Note that these warnings disappear if I prototype the function as

const char * err_sng(int err_nbr);

Is that legal?

yes
 
J

Jack Klein

Hi,

I am unable to compile a large body of code with extremely pedantic
compile time checks activate, so that warnings cause errors.
With GCC 3.3.1, I do this with

gcc -std=c99 -pedantic -Wall -Wunused -Werror -W -Wmissing-prototypes
-Wconversion -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align
-Wwrite-strings -c -o foo.o foo.c

(This is basically what GSL recommendsd for scientific codes.)

The problem is that I have a lot of code that generates these warnings:

foo.c:258: warning: "assignment discards qualifiers from pointer target
type"

This warning occurs when I try to return string literals (e.g., error
messages) to a calling function. Currently, I use code like

char * err_sng(const int err_nbr){
switch(err_nbr){
case 0: return "Message 0";
case 1: return "Message 1";
}
}

1. Say you have a function whose purpose is to return a constant
string literal (e.g., an error message) to a calling function.
How would you write this type of function so as not to generate
"assignment discards qualifiers" warnings?

Note that these warnings disappear if I prototype the function as

const char * err_sng(int err_nbr);

Is that legal? I suspect that qualifying a return value is a GNUism
and am not sure if there is a preferred method that avoids this
dubious prototype.

In addition to what Peter said, correctly, I wanted to address this
last question. Qualifying a return value is perfectly valid,
harmless, and useless in standard C, and is not just a GNU thing.

But you have not qualified the returned value, which is a pointer. If
you wanted to do that, you would need to code:

char * const err_sng(int err_nbr);

....which would be, as I said, valid, harmless, and useless.

What you specify here is not that the pointer is constant, but that
the characters it points to are.

Consider the two functions:

char *f1(char *cp)
{
return cp;
}

const char *f2(char *cp)
{
return cp;
}

Given the above function definitions/prototypes and this definition:

char non_const [] = "Hello, World!";

*f1(non_const) = 'h'; /* legal, changes to "hello, World!" */

*f2(non_const) = 'h'; /* illegal, requires diagnostic */

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
B

Ben Pfaff

Charlie Zender said:
Hi,

I am unable to compile a large body of code with extremely pedantic
compile time checks activate, so that warnings cause errors.
With GCC 3.3.1, I do this with

gcc -std=c99 -pedantic -Wall -Wunused -Werror -W -Wmissing-prototypes
-Wconversion -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align
-Wwrite-strings -c -o foo.o foo.c

Here is your problem. In C, string literals have type `char []'.
When -Wwrite-strings is used, GCC is not a C compiler, because
string literals have type `const char []'. Here is the
appropriate section from the GCC manual that talks about it:

`-Wwrite-strings'
When compiling C, give string constants the type `const
char[LENGTH]' so that copying the address of one into a
non-`const' `char *' pointer will get a warning; when
compiling C++, warn about the deprecated conversion from
string constants to `char *'. These warnings will help
you find at compile time code that can try to write into
a string constant, but only if you have been very
careful about using `const' in declarations and
prototypes. Otherwise, it will just be a nuisance; this
is why we did not make `-Wall' request these warnings.

Don't use -Wwrite-strings if you want to compile C.
Note that these warnings disappear if I prototype the function as

const char * err_sng(int err_nbr);

Is that legal? I suspect that qualifying a return value is a GNUism
and am not sure if there is a preferred method that avoids this
dubious prototype.

No, `const char *' is a portable return type. I'm not sure why
you think it's a GNUism, but it isn't.
 
K

Kevin Goodsell

Peter said:
Seriously, string literals in C have a type char[], not const char[] as one
would expect when trying to modify them causes a UB. GCC probably realizes
that and tries to prevent you from doing something stupid by warning about
returning a string literal as char * without const.

<OT> gcc gives string literals the type 'const char[]' if you ask it to
by using the -Wwrite-strings option (which the OP did). Personally I
think this is a very good option to have enabled (though possibly not if
you are compiling older code). </OT>

-Kevin
 
K

Kevin Goodsell

Charlie said:
Thanks.



My experience has been that some compilers warned about qualifiers on
return values in function prototypes. This was some time ago, though,
and they may have been C++ compilers, I can't remember.
Anyway, if it's legal, then great, it fixes the problem perfectly.

That might make sense if it was something like this:

const int f(void);

Because that's silly. But in the case of a pointer, the 'const'
(depending on placement) refers to the thing pointer to, not the pointer
itself. This is perfectly reasonable, and often a good idea.

-Kevin
 
C

Charlie Zender

Ahhh. Thanks for the clarification. Now I see that I can qualify
things that return values point to, but not the return values
themselves. That makes good sense to me. And it explains why I
remember getting warnings before. I was probably trying to qualify
returned pointers rather than the values pointed to because I
remember the warning said something about the qualifiers being
useless.
 
K

Kevin Goodsell

Ben said:
Don't use -Wwrite-strings if you want to compile C.

I disagree with this. It's true that you'll be required to remove this
option for some C code, but I think it's best in new code to treat
string literals as const, regardless of whether they technically are or
not. If you do so (or intend to do so), then this option is useful.

I'd be interested to hear arguments to the contrary.

-Kevin
 
J

Jeremy Yallop

Kevin said:
I disagree with this. It's true that you'll be required to remove this
option for some C code, but I think it's best in new code to treat
string literals as const, regardless of whether they technically are or
not. If you do so (or intend to do so), then this option is useful.

I'd be interested to hear arguments to the contrary.

With -Wwrite-strings, gcc silently accepts code that requires a
diagnostic according to the standard. That is, with this option, gcc
will cleanly compile programs that a conforming implementation may
reject.

Try setting gcc loose on the following with and without the
-Wwrite-strings option.

int f(const char (*p)[])
{
return !p;
}

int main()
{
return f(&"foo");
}

(For comparison, the Tendra compiler issues an error and doesn't
generate any output:

"string.c", line 8: Error:
[ISO 6.3.2.2]: In call of function 'f'.
[ISO 6.1.2.6]: The types 'char [4]' and 'const char []' are incompatible.
[ISO 6.3.4]: Types in pointer conversion should be compatible.
[ISO 6.3.16]: Can't perform this conversion by assignment.
[ISO 6.3.2.2]: Argument 1 is converted to parameter type.
)

Jeremy.
 
C

CBFalconer

Peter said:
.... snip ...

Seriously, string literals in C have a type char[], not const
char[] as one would expect when trying to modify them causes a UB.
GCC probably realizes that and tries to prevent you from doing
something stupid by warning about returning a string literal as
char * without const.

He specifically told it to with -Wwrite-strings.
 
P

Peter Pichler

CBFalconer said:
Peter said:
Seriously, string literals in C have a type char[], not const
char[] as one would expect when trying to modify them causes a UB.
GCC probably realizes that and tries to prevent you from doing
something stupid by warning about returning a string literal as
char * without const.

He specifically told it to with -Wwrite-strings.

<OT>Thanks, someone else has already said that (I think it was Ben Pfaff).
Not being a gcc expert, I didn't know about that switch.</OT>
 

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,770
Messages
2,569,586
Members
45,097
Latest member
RayE496148

Latest Threads

Top