C/C++ Why to use unsigned char for binary data?

后端 未结 8 1067
-上瘾入骨i
-上瘾入骨i 2020-12-07 10:27

Is it really necessary to use unsigned char to hold binary data as in some libraries which work on character encoding or binary buffers? To make sense of my que

相关标签:
8条回答
  • 2020-12-07 10:53

    The signed-ness of the plain char type is implementation defined, so unless you're actually dealing with character data (a string using the platform's character set - usually ASCII), it's usually better to specify the signed-ness explicitly by either using signed char or unsigned char.

    For binary data, the best choice is most probably unsigned char, especially if bitwise operations will be performed on the data (specifically bit shifting, which doesn't behave the same for signed types as for unsigned types).

    0 讨论(0)
  • 2020-12-07 11:02

    You'll get most of your problems when comparing the contents of individual bytes:

    char c[5];
    c[0] = 0xff;
    /*blah blah*/
    if (c[0] == 0xff)
    {
        printf("good\n");
    }
    else
    {
        printf("bad\n");
    }
    

    can print "bad", because, depending on your compiler, c[0] will be sign extended to -1, which is not any way the same as 0xff

    0 讨论(0)
  • 2020-12-07 11:06

    Well, what do you call "binary data"? This is a bunch of bits, without any meaning assigned to them by that specific part of software that calls them "binary data". What's the closest primitive data type, which conveys the idea of the lack of any specific meaning to any one of these bits? I think unsigned char.

    0 讨论(0)
  • 2020-12-07 11:12

    In C the unsigned char data type is the only data type that has all the following three properties simultaneously

    • it has no padding bits, that it where all storage bits contribute to the value of the data
    • no bitwise operation starting from a value of that type, when converted back into that type, can produce overflow, trap representations or undefined behavior
    • it may alias other data types without violating the "aliasing rules", that is that access to the same data through a pointer that is typed differently will be guaranteed to see all modifications

    if these are the properties of a "binary" data type you are looking for, you definitively should use unsigned char.

    For the second property we need a type that is unsigned. For these all conversion are defined with modulo arihmetic, here modulo UCHAR_MAX+1, 256 in most 99% of the architectures. All conversion of wider values to unsigned char thereby just corresponds to truncation to the least significant byte.

    The two other character types generally don't work the same. signed char is signed, anyhow, so conversion of values that don't fit it is not well defined. char is not fixed to be signed or unsigned, but on a particular platform to which your code is ported it might be signed even it is unsigned on yours.

    0 讨论(0)
  • 2020-12-07 11:12

    Is it really necessary to use unsigned char to hold binary data as in some libraries which work on character encoding or binary buffers?

    "really" necessary? No.

    It is a very good idea though, and there are many reasons for this.

    Your example uses printf, which not type-safe. That is, printf takes it's formatting cues from the format string and not from the data type. You could just as easily tried:

    printf("%s\n", (void*)c);
    

    ... and the result would have been the same. If you try the same thing with c++ iostreams, the result will be different (depending on the signed-ness of c).

    What reasoning could possibly advocate the use of unsigned char instead of a plain char?

    Signed specifies that the most significant bit of the data (for unsigned char the 8-th bit) represents the sign. Since you obviously do not need that, you should specify your data is unsigned (the "sign" bit represents data, not the sign of the other bits).

    0 讨论(0)
  • 2020-12-07 11:13

    Bytes are usually intended as unsigned 8 bit wide integers.

    Now, char doesn't specify the sign of the integer: on some compilers char could be signed, on other it may be unsigned.

    If I add a bit shift operation to the code you wrote, then I will have an undefined behaviour. The added comparison will also have an unexpected result.

    char c[5], d[5];
    c[0] = 0xF0;
    c[1] = 0xA4;
    c[2] = 0xAD;
    c[3] = 0xA2;
    c[4] = '\0';
    c[0] >>= 1; // If char is signed, will the 7th bit go to 0 or stay the same?
    
    bool isBiggerThan0 = c[0] > 0; // FALSE if char is signed!
    
    printf("%s\n", c);
    memcpy(d, c, 5);
    printf("%s\n", d);
    

    Regarding the warning during the compilation: if the char is signed then you are trying to assign the value 0xf0, which cannot be represented in the signed char (range -128 to +127), so it will be casted to a signed value (-16).

    Declaring the char as unsigned will remove the warning, and is always good to have a clean build without any warning.

    0 讨论(0)
提交回复
热议问题