What do these warnings mean?

  • Thread starter Walter Dnes (delete the 'z' to get my real address
  • Start date
W

Walter Dnes (delete the 'z' to get my real address

I'm trying to initialize an array of error messages, so that I can
print out an error message by using the 'nth string in an array, e.g.

printf("%s\n", messages[n]);

I'm still hazy on arrays of pointers to strings, so you may want to
finish your drinks before examining my code. Here's a small sample
program.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *messages[4] = {"Hell", "o", " ", "world"};
printf("%s%s%s%s%s\n", messages[1], messages[2],
messages[0], messages[2], messages[3] );
return EXIT_SUCCESS;
}

Compiled under gcc in excruciatingly ansi mode (-ansi -pedantic, and a
few other esoteric options as well), it gives...

[20:21:02][/misc/home/user2/tbrg] ./test1
o Hell world

That's what I expected. But the compiler gives the following
warnings, related to the "char *messages[4]" declaration...

test1.c: In function `main':
test1.c:6: warning: initialization discards qualifiers from pointer target type
test1.c:6: warning: initialization discards qualifiers from pointer target type
test1.c:6: warning: initialization discards qualifiers from pointer target type
test1.c:6: warning: initialization discards qualifiers from pointer target type

Since gcc's warnings have spotted a few "legal" howlers of mine
already, I take them seriously. What am I doing wrong, and how can I
correct it ?
 
D

Daniel =?ISO-8859-1?Q?Sch=FCle?=

[...]
That's what I expected. But the compiler gives the following
warnings, related to the "char *messages[4]" declaration...

i cant tell you for sure, but i suppose it is the absence of const what gcc
tries to tell you (but it still perfectly valid C, K&R at least)
try to declare it

const char * foo[] = {"1", "2", "3", "4"};

C compiler must accept
char * c = "12345";
but you are not allowed to change the values (not in C89, C99)
c[0] = 2;

that is why, the prefered and clenn way should be
const char * c ="12345";
c[0] = 2; // <--error

my 50 cent
 
C

CBFalconer

Walter Dnes (delete the 'z' to get my real address) said:
I'm trying to initialize an array of error messages, so that I can
print out an error message by using the 'nth string in an array, e.g.
.... snip ...
{
char *messages[4] = {"Hell", "o", " ", "world"}; .... snip ...

That's what I expected. But the compiler gives the following
warnings, related to the "char *messages[4]" declaration...

test1.c: In function `main':
test1.c:6: warning: initialization discards qualifiers from pointer target type .... snip ...

Since gcc's warnings have spotted a few "legal" howlers of mine
already, I take them seriously. What am I doing wrong, and how
can I correct it ?

Define that array as "const char *messages[4] = ...." Those
messages are unmodifiable. Say so.
 
C

Chris Torek

char *messages[4] = {"Hell", "o", " ", "world"};
Compiled under gcc in excruciatingly ansi mode (-ansi -pedantic, and a
few other esoteric options as well), it gives...[/QUOTE]

One of those "esoteric" options was, presumably, "-Wwrite-strings".

In C, a string literal[%] produces an "array N of char" object,
where N is one more than the number of characters inside the literal
-- the extra 1 is for the terminating '\0'. It is quite OK to use
the value of the object to initialize a "char *" variable:

char *p = "zorg";

The type of the anonymous "ought to have been", but for historical
reasons is not, "array N of const char". Notice the extra "const"
here. If it *had* been, the above would clearly be shorthand for:

/* str00007 is because (apparently) there were 6 other
string literals earlier. */
static const char str00007[] = { 'z', 'o', 'r', 'g', '\0' };
char *p = &str00007[0];

and *this* would require a diagnostic such as:
warning: initialization discards qualifiers from pointer target type

because &str00007[0] is "const char *", but p is just plain "char *"
-- the "const"-qualifier is missing.

Now, the peculiar thing about string literals in ANSI C is, they
really *are* read-only -- if you write on one, the effect is
undefined, and a "good" system such as a BSD or Linux will give
you a runtime trap. Yet, even though they are read-only, and the
"const" keyword *means* read-only, they do not have the "const"
attribute. This is for historical compatibility: before the 1989
C standard, there *was* no "const" keyword. Programmers just had
to be careful not to write on read-only objects. Hence, the world
is full of (perfectly good) C code that does not *use* "const".

GCC's "-Wwrite-strings" flag tells gcc that you, the programmer,
want the missing "const" stuck in. If you do this, you will get
warnings where none are required. It is quite OK to use a plain
"char *" to point at a string literal, and such code does exist,
so this warning could be annoying. Still, you have to be careful
not to write on it:

char *p = "zorg";

is fine; you just have to make sure you do not, later, try to do
something like:

p[0] = 'Z'; /* oops, was supposed to be uppercase */

If you make p have type "const char *", the compiler will be able
to catch this mistake at compile-time, and the code will compile
cleanly both with and without "-Wwrite-strings".

GCC's optional warning gives you a choice: "warn me about missing
`const's so I do not forget and try to write through the pointer",
or "do not warn me about this, because it is OK if I do not forget,
and the warning is annoying". You get to decide which of these
holds true for your own code.
 
M

Martin Ambuhl

Walter Dnes (delete the 'z' to get my real address) wrote:
[..]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *messages[4] = {"Hell", "o", " ", "world"};
printf("%s%s%s%s%s\n", messages[1], messages[2],
messages[0], messages[2], messages[3] );
return EXIT_SUCCESS;
}

Compiled under gcc [...]
the compiler gives the following
warnings, related to the "char *messages[4]" declaration...

So what does this do?

#include <stdio.h>
#include <string.h>
int main(void)
{
const char *messages[] = { "Hell", "o", " ", "world" };
printf("%s%s%s%s%s\n", messages[1], messages[2],
messages[0], messages[2], messages[3]);
return 0;
}
 
W

Walter Dnes (delete the 'z' to get my real address

The unanimous consenus from the replies is that I'm missing "const" in
the declaration. I got rid of the warnings by changing it to...

const char *messages[] = {"Hell", "o", " ", "world"};

As someone correctly deduced, one of my "esoteric options" was
"-Wwrite-strings". Because I'm using it to set up error messages in the
app I'm currently doing, "const" is OK, and a nice sanity-check. For
future reference, in case I do have to initialize at runtime, the
following compiles+runs without warnings. Other than the fact that it's
a trivial example, any comments/suggestions ?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *messages[4];

char string_a[5];
char string_b[2];
char string_c[2];
char string_d[6];

strcpy(string_a, "Hell");
strcpy(string_b, "o");
strcpy(string_c, " ");
strcpy(string_d, "world");

messages[0] = string_a;
messages[1] = string_b;
messages[2] = string_c;
messages[3] = string_d;

printf("%s%s%s%s%s\n", messages[1], messages[2],
messages[0], messages[2], messages[3] );
return EXIT_SUCCESS;
}
 
A

Al Bowers

Walter said:
The unanimous consenus from the replies is that I'm missing "const" in
the declaration. I got rid of the warnings by changing it to...

const char *messages[] = {"Hell", "o", " ", "world"};

As someone correctly deduced, one of my "esoteric options" was
"-Wwrite-strings". Because I'm using it to set up error messages in the
app I'm currently doing, "const" is OK, and a nice sanity-check. For
future reference, in case I do have to initialize at runtime, the
following compiles+runs without warnings. Other than the fact that it's
a trivial example, any comments/suggestions ?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *messages[4];

char string_a[5];
char string_b[2];
char string_c[2];
char string_d[6];

strcpy(string_a, "Hell");
strcpy(string_b, "o");
strcpy(string_c, " ");
strcpy(string_d, "world");

This will work, however, you can omit the strcpy statements
by initializing the char arrays on declaration.

char string_a[5] = "Hell";
etc
or
char string_a[] = "Hell";
char string_b[] = "o";
char string_c[] = " ";
char string_d[] = "world";


messages[0] = string_a;
messages[1] = string_b;
messages[2] = string_c;
messages[3] = string_d;

printf("%s%s%s%s%s\n", messages[1], messages[2],
messages[0], messages[2], messages[3] );
return EXIT_SUCCESS;
}
 
D

Dan Pop

In said:
I'm trying to initialize an array of error messages, so that I can
print out an error message by using the 'nth string in an array, e.g.

printf("%s\n", messages[n]);

I'm still hazy on arrays of pointers to strings, so you may want to
finish your drinks before examining my code. Here's a small sample
program.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *messages[4] = {"Hell", "o", " ", "world"};
printf("%s%s%s%s%s\n", messages[1], messages[2],
messages[0], messages[2], messages[3] );
return EXIT_SUCCESS;
}

Compiled under gcc in excruciatingly ansi mode (-ansi -pedantic, and a
few other esoteric options as well), it gives...

NEVER ever use a compiler option whose meaning is not *perfectly* clear
to you... One of these esoteric options took the compiler out of
conforming ANSI mode.
[20:21:02][/misc/home/user2/tbrg] ./test1
o Hell world

That's what I expected. But the compiler gives the following
warnings, related to the "char *messages[4]" declaration...

test1.c: In function `main':
test1.c:6: warning: initialization discards qualifiers from pointer target type
test1.c:6: warning: initialization discards qualifiers from pointer target type
test1.c:6: warning: initialization discards qualifiers from pointer target type
test1.c:6: warning: initialization discards qualifiers from pointer target type

Since gcc's warnings have spotted a few "legal" howlers of mine
already, I take them seriously. What am I doing wrong, and how can I
correct it ?

Recompile the code using *only* options you do understand:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *messages[4] = {"Hell", "o", " ", "world"};
printf("%s%s%s%s%s\n", messages[1], messages[2],
messages[0], messages[2], messages[3] );
return EXIT_SUCCESS;
}
fangorn:~/tmp 86> gcc -ansi -pedantic -Wall test.c
fangorn:~/tmp 87>

See, there is nothing wrong with the code, the problem is using a gcc
inacantation you don't understand in the first place.

Dan
 
D

Dan Pop

In said:
Walter Dnes (delete the 'z' to get my real address) said:
I'm trying to initialize an array of error messages, so that I can
print out an error message by using the 'nth string in an array, e.g.
... snip ...
{
char *messages[4] = {"Hell", "o", " ", "world"}; ... snip ...

That's what I expected. But the compiler gives the following
warnings, related to the "char *messages[4]" declaration...

test1.c: In function `main':
test1.c:6: warning: initialization discards qualifiers from pointer target type ... snip ...

Since gcc's warnings have spotted a few "legal" howlers of mine
already, I take them seriously. What am I doing wrong, and how
can I correct it ?

Define that array as "const char *messages[4] = ...." Those
messages are unmodifiable. Say so.

Please engage your brain and answer the following simple question: in
standard C, what is the ultimate type his array initialisers are supposed
to have? Is this type compatible with the type of an array element?
If yes why would the const make any difference?

As it happens, the const is required by the fact that the OP is not using
his compiler in conforming mode and the initialisers have the *incorrect*
type. But this is something the OP needs to be *explicitly* explained,
otherwise your advice is downright confusing!

Dan
 
C

CBFalconer

Dan said:
.... snip ...
Define that array as "const char *messages[4] = ...." Those
messages are unmodifiable. Say so.
.... snip ...

As it happens, the const is required by the fact that the OP is
not using his compiler in conforming mode and the initialisers
have the *incorrect* type. But this is something the OP needs
to be *explicitly* explained, otherwise your advice is downright
confusing!

I happen to think the OP is using a suitable set of options for
new code, and that my reason for the revision is easily
understandable. The standard says the constants are not
necessarily modifiable. All the rest follows. He has found his
problem at compile time, rather than at some nebulous future run
time.

We can all be obscure at times, but this is not one of them. In
fact, I consider my advice to have been admirably succint. :)
 
D

Dan Pop

In said:
Dan said:
... snip ...
Define that array as "const char *messages[4] = ...." Those
messages are unmodifiable. Say so.
... snip ...

As it happens, the const is required by the fact that the OP is
not using his compiler in conforming mode and the initialisers
have the *incorrect* type. But this is something the OP needs
to be *explicitly* explained, otherwise your advice is downright
confusing!

I happen to think the OP is using a suitable set of options for
new code, and that my reason for the revision is easily
understandable. The standard says the constants are not
necessarily modifiable.

Was the OP trying to modify them anywhere? If not, what *exactly* is
your point?
All the rest follows.

Nope, nothing follows.
He has found his
problem at compile time, rather than at some nebulous future run
time.

He had no problem in the first place, his code was 100% correct.
His pseudo-problem was caused by the existence of some bogus compiler
diagnostics, caused by invoking the compiler in non-conforming mode.
We can all be obscure at times, but this is not one of them. In
fact, I consider my advice to have been admirably succint. :)

It was admirably bullshit. All the OP could learn from it was that the
const was required by the language, which is patently false.

Dan
 
C

CBFalconer

Dan said:
CBFalconer said:
Dan said:
... snip ...

Define that array as "const char *messages[4] = ...." Those
messages are unmodifiable. Say so.
... snip ...

As it happens, the const is required by the fact that the OP is
not using his compiler in conforming mode and the initialisers
have the *incorrect* type. But this is something the OP needs
to be *explicitly* explained, otherwise your advice is downright
confusing!

I happen to think the OP is using a suitable set of options for
new code, and that my reason for the revision is easily
understandable. The standard says the constants are not
necessarily modifiable.

Was the OP trying to modify them anywhere? If not, what *exactly*
is your point?
All the rest follows.

Nope, nothing follows.
He has found his problem at compile time, rather than at some
nebulous future run time.

He had no problem in the first place, his code was 100% correct.
His pseudo-problem was caused by the existence of some bogus
compiler diagnostics, caused by invoking the compiler in
non-conforming mode.
We can all be obscure at times, but this is not one of them. In
fact, I consider my advice to have been admirably succint. :)

It was admirably bullshit. All the OP could learn from it was
that the const was required by the language, which is patently
false.

On the contrary, it is true in the same sense that casting the
return value from malloc is poor practice, or that testing input
completion with feof is probably wrong. C is already quite
capable of taking sly nips at ones ankles, and the odd extra guard
is useful. The fact that it induces spurious error indications in
old code, written before the 'const' word was even a part of C, is
immaterial.

<sarcasm> To be consistent you should also advocate the use of
pre-prototype function definitions, and you should never use -W,
-Wall, -ansi, or -pedantic with gcc. </sarcasm>
 
D

Dan Pop

In said:
Dan said:
CBFalconer said:
Dan Pop wrote:

... snip ...

Define that array as "const char *messages[4] = ...." Those
messages are unmodifiable. Say so.

... snip ...

As it happens, the const is required by the fact that the OP is
not using his compiler in conforming mode and the initialisers
have the *incorrect* type. But this is something the OP needs
to be *explicitly* explained, otherwise your advice is downright
confusing!

I happen to think the OP is using a suitable set of options for
new code, and that my reason for the revision is easily
understandable. The standard says the constants are not
necessarily modifiable.

Was the OP trying to modify them anywhere? If not, what *exactly*
is your point?
All the rest follows.

Nope, nothing follows.
He has found his problem at compile time, rather than at some
nebulous future run time.

He had no problem in the first place, his code was 100% correct.
His pseudo-problem was caused by the existence of some bogus
compiler diagnostics, caused by invoking the compiler in
non-conforming mode.
We can all be obscure at times, but this is not one of them. In
fact, I consider my advice to have been admirably succint. :)

It was admirably bullshit. All the OP could learn from it was
that the const was required by the language, which is patently
false.

On the contrary, it is true in the same sense that casting the
return value from malloc is poor practice, or that testing input
completion with feof is probably wrong. C is already quite
capable of taking sly nips at ones ankles, and the odd extra guard
is useful.

But this is NOT what you told to the OP, is it? You made him believe
that the const is *required* by the language, and this is BULLSHIT.
The usage of const in that context is not even a purely stilistical issue
because it forces significant changes in other contexts, too. E.g.

fangorn:~/tmp 170> cat test.c
#include <string.h>

char *last(char *s)
{
return s + strlen(s) - 1;
}

int main(void)
{
const char *foo = "bar";
return *last(foo) - 'r';
}
fangorn:~/tmp 171> gcc test.c
test.c: In function `main':
test.c:11: warning: passing arg 1 of `last' discards qualifiers from pointer target type

Fix this code so that it compiles cleanly and post the result. Note that
changing the return type of last() is NOT an option, as the function is
also supposed to be passed non constant strings as arguments and its
return value should be usable for modifying those strings. Just like
strchr().

Needless to say, my example would be perfectly correct without the const
in the definition of foo. Preserving this const requires the introduction
of a very ugly pointer cast in last().

So, cut the crap about the usefulness of the "odd extra guard".
The fact that it induces spurious error indications in
old code, written before the 'const' word was even a part of C, is
immaterial.

What old code are you talking about?
<sarcasm> To be consistent you should also advocate the use of
pre-prototype function definitions, and you should never use -W,
-Wall, -ansi, or -pedantic with gcc. </sarcasm>

Your sarcasm is misplaced (as usual). The OP did use -ansi -pedantic
therefore he was NOT interested in writing pre-ANSI code. Neither am I.

In C, more often than not, const is a cure much worse than the disease.
It is, probably, the very last feature that should be taught to the
newbie, along with an explanation that it actually means "read only" and
comes with an array of strings [sic] attached. I have a lot of respect
for whoever coined the term "const poisoning".

Dan
 
C

Chris Torek

In C, more often than not, const is a cure much worse than the disease.
It is, probably, the very last feature that should be taught to the
newbie, along with an explanation that it actually means "read only" and
comes with an array of strings [sic] attached. I have a lot of respect
for whoever coined the term "const poisoning".

That was Henry Spencer, if I recall correctly.

(I still believe "const" should have been inserted as a storage-class
modifier rather than a type-qualifier, with the type system ignoring
"const"-ness entirely. The type attributes of string literals
simply do not work right; and things get even hairier when one
tries to deal with, e.g., "char **argv" and "const char *const *"
parameters. The latter "works right" in C++, but not in C.)
 
C

CBFalconer

Dan said:
.... snip ...

But this is NOT what you told to the OP, is it? You made him
believe that the const is *required* by the language, and this is
BULLSHIT. The usage of const in that context is not even a purely
stilistical issue because it forces significant changes in other
.... snip ...

Following is my original advice, allowing this to be snipped:
Define that array as "const char *messages[4] = ...." Those
messages are unmodifiable. Say so.

Have you any disagreement with the fact that those quoted string
messages (represented by the .....) are unmodifiable? I told the
OP to state that fact.
 
D

Dan Pop

In said:
Dan said:
... snip ...

But this is NOT what you told to the OP, is it? You made him
believe that the const is *required* by the language, and this is
BULLSHIT. The usage of const in that context is not even a purely
stilistical issue because it forces significant changes in other
... snip ...

Following is my original advice, allowing this to be snipped:
Define that array as "const char *messages[4] = ...." Those
messages are unmodifiable. Say so.

Have you any disagreement with the fact that those quoted string
messages (represented by the .....) are unmodifiable? I told the
OP to state that fact.

If you believe that going in circles after losing a debate is the right
thing to do, I have even less respect for you.

I have already clearly explained to you what's wrong with your advice
and I'm not going to repeat myself. Reread the thread.

Dan
 

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

Similar Threads

fixing compile warnings 9
ctime_r() warnings 3
when to ignore warnings 1
const, typedef, and warning 14
what does this warning mean ? 106
const problem 1
Const Issue 2
what does this mean?? 3

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top