gcc 4 signed vs unsigned char

J

juanitofoo

Hello,
I've just switched to gcc 4 and I came across a bunch of warnings that
I can't fix. Example:

#include <stdio.h>

int main()
{
signed char *p = "Hola";

return 0;
}

If I compile that file, I get:
kk.c: In function 'main':
kk.c:5: warning: pointer targets in initialization differ in signedness

Only if I remove the signed from the declaration it compiles without
errors. How can I use the signed or unsigned char?

I'm using gcc 4.0.1. The reason for asking this is because in one
program I'm always using int8_t and u_int8_t values, and both of them
are signed or unsigned, no simply 'char' variables.

Thanks in advance.
 
G

guorke

Hello,
I've just switched to gcc 4 and I came across a bunch of warnings that
I can't fix. Example:

#include <stdio.h>

int main()
{
signed char *p = "Hola";

return 0;
}

If I compile that file, I get:
kk.c: In function 'main':
kk.c:5: warning: pointer targets in initialization differ in signedness

Only if I remove the signed from the declaration it compiles without
errors. How can I use the signed or unsigned char?

I'm using gcc 4.0.1. The reason for asking this is because in one
program I'm always using int8_t and u_int8_t values, and both of them
are signed or unsigned, no simply 'char' variables.

Thanks in advance.

in gcc 3.4. it's ok!
 
M

Michael Mair

Hello,
I've just switched to gcc 4 and I came across a bunch of warnings that
I can't fix. Example:

#include <stdio.h>

int main()
{
signed char *p = "Hola";

return 0;
}

If I compile that file, I get:
kk.c: In function 'main':
kk.c:5: warning: pointer targets in initialization differ in signedness

Only if I remove the signed from the declaration it compiles without
errors. How can I use the signed or unsigned char?

I'm using gcc 4.0.1. The reason for asking this is because in one
program I'm always using int8_t and u_int8_t values, and both of them
are signed or unsigned, no simply 'char' variables.

The type char is - for historical reasons - distinct from signed char
and unsigned char and may be effectively (signedness, size, range)
either the one or the other.
So, only
char *p = "Hola";
is always correct.


Cheers
Michael
 
K

Keith Thompson

I've just switched to gcc 4 and I came across a bunch of warnings that
I can't fix. Example:

#include <stdio.h>

int main()
{
signed char *p = "Hola";

return 0;
}

If I compile that file, I get:
kk.c: In function 'main':
kk.c:5: warning: pointer targets in initialization differ in signedness

Only if I remove the signed from the declaration it compiles without
errors. How can I use the signed or unsigned char?

I'm using gcc 4.0.1. The reason for asking this is because in one
program I'm always using int8_t and u_int8_t values, and both of them
are signed or unsigned, no simply 'char' variables.

Why would you want to use either signed char or int8_t for a character
string? The correct declaration is

char *p = "Hola";

"Plain" char is a distinct type from both signed char and unsigned
char, though it has the same representation as one of them.

However, the warning is misleading. The initialization is illegal (a
constraint violation), but the pointer targets don't actually differ
in signedness. I've just submitted a bug report; see
<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23087>.
 
M

Me

Hello,
I've just switched to gcc 4 and I came across a bunch of warnings that
I can't fix. Example:

#include <stdio.h>

int main()
{
signed char *p = "Hola";

return 0;
}

If I compile that file, I get:
kk.c: In function 'main':
kk.c:5: warning: pointer targets in initialization differ in signedness

Only if I remove the signed from the declaration it compiles without
errors.

"Hola" is a const char[5] which can be implicitly converted to const
char * and also unfortunately to just char *. What makes you think it
can also be implicitly converted to signed char *?

It's best to just think of unsigned char as the native byte type,
signed char as the corresponding signed integer, and plain char as a
separate native character type that just happens to be required to be
represented by either an unsigned char or signed char. It's unfortunate
it is this way but it's very, very unlikey to change.
How can I use the signed or unsigned char?

static signed char hola[] = "Hola";
signed char *p = hola;

Maybe you're confused why this works but your example doesn't. It's
because this is just syntax sugar for:

static signed char hola[5] = { 'H', 'o', 'l', 'a', '\0' };
signed char *p = hola;

(you can also get rid of the static and/or add a const qualifier. I
don't know how your actual code looks like from this small snippet)
I'm using gcc 4.0.1. The reason for asking this is because in one
program I'm always using int8_t and u_int8_t values, and both of them
are signed or unsigned, no simply 'char' variables.

who said int8_t and uint8_t must be typedeffed to a character type in
the first place? Consider it a good thing you get this warning (it
would be better if it was an error instead).
 
E

Eric Sosman

Me said:
Hello,
I've just switched to gcc 4 and I came across a bunch of warnings that
I can't fix. Example:

#include <stdio.h>

int main()
{
signed char *p = "Hola";

return 0;
}

If I compile that file, I get:
kk.c: In function 'main':
kk.c:5: warning: pointer targets in initialization differ in signedness

Only if I remove the signed from the declaration it compiles without
errors.


"Hola" is a const char[5] which can be implicitly converted to const
char * and also unfortunately to just char *.

Almost, but not quite. "Hola" is a char[5] that decays
to char* in most circumstances. Neither the array nor the
pointer is const-qualified, even though it is forbidden to
try to modify the array.
 
O

Old Wolf

Hello,
I've just switched to gcc 4 and I came across a bunch of warnings that
I can't fix. Example:

#include <stdio.h>

int main()
{
signed char *p = "Hola";

return 0;
}

If I compile that file, I get:
kk.c: In function 'main':
kk.c:5: warning: pointer targets in initialization differ in signedness

Only if I remove the signed from the declaration it compiles without
errors. How can I use the signed or unsigned char?

You should write code that works just as well whether plain char
is signed or not.
I'm using gcc 4.0.1. The reason for asking this is because in one
program I'm always using int8_t and u_int8_t values, and both of them
are signed or unsigned, no simply 'char' variables.

You could avoid the warning with:
signed char *p = (signed char *)"Hola";

However I can't think of a reason why you would prefer this
to:
char const *p = "Hola";

Can you post some code that demonstrates why you need to
point to non-const, signed chars?
 
K

Keith Thompson

Eric Sosman said:
Me wrote: [...]
"Hola" is a const char[5] which can be implicitly converted to const
char * and also unfortunately to just char *.

Almost, but not quite. "Hola" is a char[5] that decays
to char* in most circumstances. Neither the array nor the
pointer is const-qualified, even though it is forbidden to
try to modify the array.

"Forbidden" in the sense that attempting to do so invokes undefined
behavior. For some implementations, this is indistinguishable from it
being allowed.
 
O

Old Wolf

Keith said:
However, the warning is misleading. The initialization is illegal (a
constraint violation), but the pointer targets don't actually differ
in signedness. I've just submitted a bug report...

I, for one, am happy with the warning issued: "definitely signed"
is different to "maybe signed".

Plus the OP didn't indicate whether his implementation has plain
char signed or not, and if plain char were unsigned, then the
warning is definitely correct. GCC has a switch for that, and I
also think it defaults to unsigned on appropriate platforms
(eg. ARM).
 
K

Keith Thompson

Old Wolf said:
I, for one, am happy with the warning issued: "definitely signed"
is different to "maybe signed".

But "signed though it's not required to be" and "signed because it's
required to be" don't "differ in signedness". The message should say
that they differ in type.

If I saw that message and didn't know that plain char is signed, I
would naturally assume that the compiler is complaining because plain
char is unsigned. If I found that plain char really is unsigned, I'd
submit a bug report against the compiler. (In fact, I did!)
Plus the OP didn't indicate whether his implementation has plain
char signed or not, and if plain char were unsigned, then the
warning is definitely correct. GCC has a switch for that, and I
also think it defaults to unsigned on appropriate platforms
(eg. ARM).

The warning wouldn't be as incorrect if plain char were unsigned, but
it would still be misleading. The initialization is illegal because
the pointer types are incompatible (and the pointer types are
incompatible because the target types are distinct types), *not*
just because the target types differ in signedness.

gcc 4.0.0 produces the warning "pointer targets in initialization
differ in signedness" for both of the following lines:

signed char *ps = "signed?";
unsigned char *pu = "unsigned?";
 
E

Eric Sosman

Keith said:
Eric Sosman said:
Me wrote:
[...]
"Hola" is a const char[5] which can be implicitly converted to const
char * and also unfortunately to just char *.

Almost, but not quite. "Hola" is a char[5] that decays
to char* in most circumstances. Neither the array nor the
pointer is const-qualified, even though it is forbidden to
try to modify the array.


"Forbidden" in the sense that attempting to do so invokes undefined
behavior. For some implementations, this is indistinguishable from it
being allowed.

True: "undefined" is undefined. My point is that there
is no const qualifier to warn one away from attempting the
unthinkable.

If one were re-designing C "from the ground up" today,
string literals would surely be const-qualified. They are
not, though. The Rationale says

[...] string literals do not have the type /array of
const char/ in order to avoid problems of pointer type
checking, particularly with library functions, since
assigning a /pointer to const char/ to a plain /pointer
to char/ is not valid.

That is, prior to C89 there was no way to say "const" in a C
program. Nowadays if you write a function taking a string
argument that the function does not modify, you use the type
"const char*" for the argument. But the huge body of pre-C89
code had to type such arguments as simply "char*" -- and if
C89 had changed the type of string literals to "const char"
it would have suddenly broken all that pre-existing code. As
the Rationale says elsewhere, "Existing code is important,
existing implementations are not." A brand-new Standard that
provoked compilation errors in practically every existing
perfectly good program might have met some resistance to wide
adoption ... It's as if the Standard had not only permitted
but required the use of function prototypes: no project manager
in his right mind would have chosen to adopt a Standard whose
only effect was to create expensive busy-work for his staff.

String literals are non-const for "hysterical raisins."
This is not the only C feature with such a rationale.
 
G

Gordon Burditt

That is, prior to C89 there was no way to say "const" in a C
program. Nowadays if you write a function taking a string
argument that the function does not modify, you use the type
"const char*" for the argument.

Except there's still a problem. Take a function which returns a
pointer *INTO* one of its arguments (or possibly NULL). Examples
in the C library include strchr(), strrchr(), and strstr(), but you
can imagine lots of parsing functions that do that. Now, if you
pass in a const-poisoned pointer, it needs to be const-poisoned in
the return type. If you pass in a non-const-poisoned pointer, it
needs to be not const-poisoned on the way out, so you can use it
to write on the string. I need two nearly-identical copies of every
type of this function, one const-poisoned, the other not? Yeech.
C isn't C++ with its overloading.

Regardless of any existing code, this is still a problem.

Gordon L. Burditt
 
J

juanitofoo

Old Wolf ha escrito:
You should write code that works just as well whether plain char
is signed or not.


You could avoid the warning with:
signed char *p = (signed char *)"Hola";

However I can't think of a reason why you would prefer this
to:
char const *p = "Hola";

Can you post some code that demonstrates why you need to
point to non-const, signed chars?

The reason is just that I'm using always int8_t instead of char, is
that correct and portable for all platforms? (int8_t is a signed char)
 
K

Keith Thompson

Old Wolf ha escrito:

The reason is just that I'm using always int8_t instead of char, is
that correct and portable for all platforms? (int8_t is a signed char)

Your problem is simple: you're using int8_t instead of char.

The solution is equally simple: use char.

Is there some reason you're using int8_t when char is more appropriate?
 
C

Clark S. Cox III

Old Wolf ha escrito:

The reason is just that I'm using always int8_t instead of char, is
that correct and portable for all platforms? (int8_t is a signed char)

The question is: "Why?"
Why are you using int8_t?
 
C

CBFalconer

Old Wolf ha escrito:
.... snip ...

The reason is just that I'm using always int8_t instead of char,
is that correct and portable for all platforms? (int8_t is a
signed char)

No, it is not. int_8t need not even be available on all
platforms. char will be available.
 
O

Old Wolf

Keith said:
gcc 4.0.0 produces the warning "pointer targets in initialization
differ in signedness" for both of the following lines:

signed char *ps = "signed?";
unsigned char *pu = "unsigned?";

I don't pretend to speak for anyone else here, but for me that
error message is more informative and allows me to understand
the error more quickly than "pointer targets are incompatible"
would.
 
J

juanitofoo

Keith Thompson ha escrito:
Your problem is simple: you're using int8_t instead of char.

The solution is equally simple: use char.

Is there some reason you're using int8_t when char is more appropriate?

I've always thought that using int8_t would be more portable, but it
seems I was wrong. I'll change my code to use char then :) Thanks for
everything.
 
J

juanitofoo

I thougth that using int8_t would be more portable. Anyway, in my code
I also use int8_t, int16_t, int32_t (and their unsigned versions)
instead of using int, short, long ... Should I use the intx_t or the
int, short, etc? My main aim is portability among platforms.
 
V

Villy Kruse

I thougth that using int8_t would be more portable. Anyway, in my code
I also use int8_t, int16_t, int32_t (and their unsigned versions)
instead of using int, short, long ... Should I use the intx_t or the
int, short, etc? My main aim is portability among platforms.

It is! If it is important that the type is exactly 8 bits. If
the program is compiled on a system which doesn't support 8 bit integer
types the compile would fail, which is actualy better than it silently
fails during execution. If it is not important that the type being
exactly 8 bits, then use char.

Villy
 

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,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top