gcc 4 signed vs unsigned char

Discussion in 'C Programming' started by juanitofoo, Jul 26, 2005.

  1. juanitofoo

    juanitofoo Guest

    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.
     
    juanitofoo, Jul 26, 2005
    #1
    1. Advertisements

  2. juanitofoo

    guorke Guest

    in gcc 3.4. it's ok!
     
    guorke, Jul 26, 2005
    #2
    1. Advertisements

  3. juanitofoo

    Michael Mair Guest

    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
     
    Michael Mair, Jul 26, 2005
    #3
  4. 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>.
     
    Keith Thompson, Jul 26, 2005
    #4
  5. juanitofoo

    Me Guest

    "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.
    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)
    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).
     
    Me, Jul 26, 2005
    #5
  6. juanitofoo

    Eric Sosman Guest

    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.
     
    Eric Sosman, Jul 26, 2005
    #6
  7. juanitofoo

    Old Wolf Guest

    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?
     
    Old Wolf, Jul 26, 2005
    #7
  8. "Forbidden" in the sense that attempting to do so invokes undefined
    behavior. For some implementations, this is indistinguishable from it
    being allowed.
     
    Keith Thompson, Jul 26, 2005
    #8
  9. juanitofoo

    Old Wolf Guest

    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).
     
    Old Wolf, Jul 27, 2005
    #9
  10. 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!)
    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?";
     
    Keith Thompson, Jul 27, 2005
    #10
  11. juanitofoo

    Eric Sosman Guest

    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.
     
    Eric Sosman, Jul 27, 2005
    #11
  12. That is, prior to C89 there was no way to say "const" in a C
    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
     
    Gordon Burditt, Jul 27, 2005
    #12
  13. juanitofoo

    juanitofoo Guest

    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)
     
    juanitofoo, Jul 27, 2005
    #13
  14. 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?
     
    Keith Thompson, Jul 27, 2005
    #14
  15. The question is: "Why?"
    Why are you using int8_t?
     
    Clark S. Cox III, Jul 27, 2005
    #15
  16. juanitofoo

    CBFalconer Guest

    No, it is not. int_8t need not even be available on all
    platforms. char will be available.
     
    CBFalconer, Jul 27, 2005
    #16
  17. juanitofoo

    Old Wolf Guest

    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.
     
    Old Wolf, Jul 28, 2005
    #17
  18. juanitofoo

    juanitofoo Guest

    Keith Thompson ha escrito:
    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.
     
    juanitofoo, Jul 28, 2005
    #18
  19. juanitofoo

    juanitofoo Guest

    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.
     
    juanitofoo, Jul 28, 2005
    #19
  20. juanitofoo

    Villy Kruse Guest

    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
     
    Villy Kruse, Jul 28, 2005
    #20
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.