Warning when comparing char[] to a #define'd string

A

Andreas Eibach

Hi,

let's say I have this:

#include <string.h>

#define BLAH "foo"

Later on, I do this:

unsigned char yadda [10];

/* ... get a couple of bytes ( = string) from buffer ... */

if (strcmp (BLAH, yadda) == 0) { printf ("yeehaw!\n"); }

This gives me the following warning:
warning: pointer targets in passing argument 1 of 'strcmp' differ in
signedness
I'm asking because I do not know about signed or unsigned in _quoted_
#define's.
Also several attempts of casting the stuff (both arg#1 + arg#2) failed.
Seems to be a gcc 4-only default to check this.
(I bet this was there in gcc3 also, it was just not enabled by default)

Thanks,
Andreas
 
S

Stephen Sprunk

Andreas said:
let's say I have this:

#include <string.h>

#define BLAH "foo"

Later on, I do this:

unsigned char yadda [10];

/* ... get a couple of bytes ( = string) from buffer ... */

if (strcmp (BLAH, yadda) == 0) { printf ("yeehaw!\n"); }

This is no different from:

#include <string.h>

unsigned char yadda [10];

/* ... get a couple of bytes ( = string) from buffer ... */

if (strcmp ("foo", yadda) == 0) { printf ("yeehaw!\n"); }
This gives me the following warning:
warning: pointer targets in passing argument 1 of 'strcmp' differ in
signedness

You're comparing a (char *) and an (unsigned char *). The warning makes
sense. If yadda contains a string, it should be a char[], not an
unsigned char[].
I'm asking because I do not know about signed or unsigned in _quoted_
#define's.

The #define is irrelevant. See the simplification above.
Also several attempts of casting the stuff (both arg#1 + arg#2) failed.

Casting "foo" to (unsigned char *) or casting yadda to (char *) should
mask the warning, but the better solution is to use the correct types.
Seems to be a gcc 4-only default to check this.
(I bet this was there in gcc3 also, it was just not enabled by default)

Possibly; ask the GCC folks.

char might be unsigned on your system, but even so "char" and "unsigned
char" aren't exactly the same thing. It's not like "int" and "signed
int" being the same.

S
 
A

Andreas Eibach

Stephen Sprunk said:
You're comparing a (char *) and an (unsigned char *). The warning makes
sense. If yadda contains a string, it should be a char[], not an
unsigned char[].
I'm asking because I do not know about signed or unsigned in _quoted_
#define's.

The #define is irrelevant. See the simplification above.
OK.
Also several attempts of casting the stuff (both arg#1 + arg#2) failed.

Casting "foo" to (unsigned char *) or casting yadda to (char *) should
mask the warning, but the better solution is to use the correct types.

Thanks for the tip - I did a few tests with modified code.
Three variations tested, two of them work, with one of the latter needing an
additional malloc().

Now it comes : :))

[variation #1+#2]

#include <string.h>

#define BLAH "foo"
char * yadda; /* variation #2: char yadda[10]; */

....malloc ()... /* for variation #2: do not use */

/* ... get a couple of bytes ( = string) from buffer ...*/

if (strcmp (BLAH, yadda) == 0) { printf ("yeehaw!\n"); }

both WORK!

BUT

[variation #3]
#include <string.h>

#define BLAH (unsigned char*) "foo"
....
unsigned char yadda[10]; /* unsigned char* ^= unsigned char[] */

/* ... get a couple of bytes ( = string) from buffer ... */
if (strcmp (BLAH, yadda) == 0) { printf ("yeehaw!\n"); }

gives me even TWO warnings!

So I will stick to using _signed_ char* in the strcmp(), even though I'm not
needing negative values.
Looks like strcmp() does not accept unsigned char*, even though both
arguments are now of same type.
Possibly; ask the GCC folks.

Could be a good idea.
Thanks for the reply,

-Andreas
 
F

Flash Gordon

Stephen Sprunk wrote, On 07/11/08 17:52:
Andreas said:
let's say I have this:

#include <string.h>

#define BLAH "foo"

Later on, I do this:

unsigned char yadda [10];

/* ... get a couple of bytes ( = string) from buffer ... */

if (strcmp (BLAH, yadda) == 0) { printf ("yeehaw!\n"); }
This gives me the following warning:
warning: pointer targets in passing argument 1 of 'strcmp' differ in
signedness

You're comparing a (char *) and an (unsigned char *). The warning makes
sense. If yadda contains a string, it should be a char[], not an
unsigned char[].

No he isn't, he is passing both to a function that expects to pointers
to char (not unsigned or signed but plain) which happens to do a comparison.
The #define is irrelevant. See the simplification above.


Casting "foo" to (unsigned char *) or casting yadda to (char *) should
mask the warning, but the better solution is to use the correct types.

Casting the string literal will just make matters worse because then it
will be two pointers which don't match in signedness instead of just one.
Possibly; ask the GCC folks.

It isn't enabled by default on my machine with gcc 4.3.2. It is enabled
if I specify -ansi -pedantic, which is correct as a diagnostic is required.
char might be unsigned on your system, but even so "char" and "unsigned
char" aren't exactly the same thing. It's not like "int" and "signed
int" being the same.

Casting yadda to char* removes the warning on my machine, but I would
seriously consider whether it should be plain char.
 
F

Flash Gordon

Andreas Eibach wrote, On 07/11/08 19:10:
"Stephen Sprunk" <[email protected]> wrote:

/* ... get a couple of bytes ( = string) from buffer ... */
if (strcmp (BLAH, yadda) == 0) { printf ("yeehaw!\n"); }

gives me even TWO warnings!

See my other reply.
So I will stick to using _signed_ char* in the strcmp(), even though I'm not
needing negative values.

Plain char is NOT signed char. On some systems it happens to be signed,
on some it is unsigned, but it is ALWAYS a distinct type from both.

Always use plain char for character data *unless* there is a specific
good reason to use something else.
Looks like strcmp() does not accept unsigned char*, even though both
arguments are now of same type.

<snip>

See my other reply.
 
C

CBFalconer

Andreas said:
.... snip ...

So I will stick to using _signed_ char* in the strcmp(), even
though I'm not needing negative values. Looks like strcmp()
does not accept unsigned char*, even though both arguments are
now of same type.

No. You should recognize that there are three distinct types of
chars in C. char, signed char, and unsigned char. They are
distinct. For any implemented C system char has been set to be one
of signed char, or unsigned char. You don't necessarily know
which. What you do know is that strings are represented by arrays
of char (with a '\0' terminator), and are passed as pointers to
char (char*).

It looks as if your system has char set to be signed char. Don't
assume this in general.
 
S

Stephen Sprunk

Andreas said:
Stephen Sprunk said:
Casting "foo" to (unsigned char *) or casting yadda to (char *) should
mask the warning, but the better solution is to use the correct types.

Thanks for the tip - I did a few tests with modified code.
Three variations tested, two of them work, with one of the latter needing an
additional malloc().

Now it comes : :))

[variation #1+#2]

#include <string.h>

#define BLAH "foo"
char * yadda; /* variation #2: char yadda[10]; */

...malloc ()... /* for variation #2: do not use */

/* ... get a couple of bytes ( = string) from buffer ...*/

if (strcmp (BLAH, yadda) == 0) { printf ("yeehaw!\n"); }

both WORK!

They work because they're correct.
BUT

[variation #3]
#include <string.h>

#define BLAH (unsigned char*) "foo"
...
unsigned char yadda[10]; /* unsigned char* ^= unsigned char[] */

/* ... get a couple of bytes ( = string) from buffer ... */
if (strcmp (BLAH, yadda) == 0) { printf ("yeehaw!\n"); }

gives me even TWO warnings!

What warnings? I presume you mean the original warning about comparing
strings with different signed-ness is gone and there are two new ones
about passing (unsigned char *)s to a function expecting (char *)s?

If I saw this code, I'd warn you, too. (unsigned char *) is not the
right type to be using with strings. It'll probably work, but it
misleads the reader as to what's going on.
So I will stick to using _signed_ char* in the strcmp(), even though I'm not
needing negative values.

No, do not use (signed char *). When working with strings, always use
(char *). Even if (char) happens to be signed on your system, it is
still a distinct type from (signed char).
Looks like strcmp() does not accept unsigned char*, even though both
arguments are now of same type.

strcmp() is specified to take two arguments of type (char *). If you
pass in (signed char *) _or_ (unsigned char *), it's not surprising that
your compiler warns you about using the wrong type. When working with
strings, always use (char *).

S
 
A

Andreas Eibach

Flash Gordon said:
Casting the string literal will just make matters worse because then it
will be two pointers which don't match in signedness instead of just one.

True. I was just trying to keep it short :) but I also did try this 4th
variation.
And of course, I got 2 warnings about non-respected signedness.


Yes, I agree I had confused and set this equal to (un)signed int.
So there are three of the char* sort. I think now I won't forget about that
anymore. You definitely never stop learning. o_o

-Andreas
 
A

Andreas Eibach

Eric Sosman said:
Are you sure the error message matches the code you have shown?
If so, report the bug[*] to your compiler vendor. (Or upgrade to a
newer version. For what it's worth, your code elicits a warning from
gcc 4.3.2,

Bingo. I was getting this with 4.3.2 indeed.
but with that version the warning is correct.)
Yup. Note that my post definitely was _not_ a complaint of that "gcc guys,
please fix your software" sort, but simply a presumption that I might have
forgotten about something. :) However, I could not sense that there are
three distinct char * types, unlike the int types which are either unsigned
or signed---thus two---and that's about it.

-Andreas
 
A

Andreas Eibach

Stephen Sprunk said:
When working with strings, always use (char *).

Promised henceforth. :)
Since I know there are 3 distinct subtypes, which blatantly escaped me. Doh.

-Andreas
 
K

Keith Thompson

CBFalconer said:
No. You should recognize that there are three distinct types of
chars in C. char, signed char, and unsigned char. They are
distinct.
Right.

For any implemented C system char has been set to be one
of signed char, or unsigned char. You don't necessarily know
which.

And here you contradict your earlier statement. I know what you
meant, but it's not quite what you said. For any C implementation,
type char isn't "set to be" either signed char or unsigned char; it's
set to have the same characteristics (size, range, representation) as
either signed char or unsigned char. It's still a distinct type, as
you correctly stated above.

For example:

char *pc = NULL;
unsigned char *puc;
signed char *psc;
puc = pc; /* constraint violation */
psc = pc; /* constraint violation */

*Both* marked lines are constraint violations, regardless of the
signedness of plain char.
What you do know is that strings are represented by arrays
of char (with a '\0' terminator), and are passed as pointers to
char (char*).

String literals certainly are. I think that the standard's definition
of "string", as "a contiguous sequence of characters terminated by and
including the first null character", allows an array of unsigned char
to contain a "string"; a "character" can be either a char, a signed
char, or an unsigned char.
It looks as if your system has char set to be signed char. Don't
assume this in general.

You mean "set to have the same representation as".
 
E

Eric Sosman

Andreas said:
Eric Sosman said:
Are you sure the error message matches the code you have shown?
If so, report the bug[*] to your compiler vendor. (Or upgrade to a
newer version. For what it's worth, your code elicits a warning from
gcc 4.3.2,

Bingo. I was getting this with 4.3.2 indeed.

Apparently I was being too subtle. Let me try again:
"Andreas, you are lying. The code you showed did *not*
elicit the warning you showed, and you are guilty of
mis-reporting. The `this' you mention was in fact
`something else'."

I'm pretty sure I know what mistake you made, and I
know what message you actually got (or, if you actually
got that message, what your code actually looked like).
The point of the scolding is simply this: When you report
that "Code X gave me message Y," do not replace X and Y
by W and Q! It's bad for the diagnosis.

"Doctor, I have this terrible pain in my left ankle."
"I see nothing wrong with your left ankle." "Oh, what I
really meant was my right hip ... maybe. Guess again."
 
A

Andreas Eibach

Eric Sosman said:
Apparently I was being too subtle. Let me try again:
"Andreas, you are lying. The code you showed did *not*
elicit the warning you showed, and you are guilty of
mis-reporting. The `this' you mention was in fact
`something else'."

Yes, Your Honor. :p

-Andreas
 

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

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top