Domanda

I would like to store an unsigned char into a char by means of a shift. As the two data types have the same length (1 byte on my machine), I would have expected the following code to work:

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

int main () {

        printf ("%d\n", sizeof(char));
        printf ("%d\n", sizeof(unsigned char));

        unsigned char test = 49;
        char testchar = (char) (test - 127);
        printf ("%x\n", testchar);

        return 0;
}

but it doesn't. In particular, I got the following output:

1
1
ffffffb2

that suggests that the char has been casted to int. Does anybody has an explanation and, hopefully, a solution?

È stato utile?

Soluzione

%x is a specifier for a 4-byte int. To print one byte char use %hhx.

printf typecasts its arguments according to the format specifiers passed to it.That is why testchar was type promoted to int.

Altri suggerimenti

printf is a variable argument function, and as such it's arguments are subject to default promotion rules. For this case, your char is promoted to an int, and in that process is sign extended. A 2's complement int of 4 bytes with the binary pattern 0xffffffb2 is -78. Print it as a char with the %hhx specifier.

See also Which integral promotions do take place when printing a char?

%x is only for printing unsigned int, however you supply a char.

Using %x with a negative value of char causes undefined behaviour.

Aside: The C Standard specification of printf is not particularly clear; some feel that passing anything except exactly an unsigned int causes undefined behaviour. Others (including myself) feel that it's OK to pass arguments that are not specifically unsigned int, but after the default argument promotions, have type int with a non-negative value. The standard does guarantee that non-negative ints have the same representation as the unsigned int with the same value.


Some of the other answers suggest %hhx, but that is not any better than %x. The standard (on a sensible interpretation) specifies that %hhx only be used with an unsigned char argument, and %hhd only be used with a signed char argument. There is actually no modifier for plain char.

Either way you look at it, nowhere can printf be used to convert negative values to positive representations in a well-defined manner. You must convert the argument yourself and then use a matching format specifier. In this case:

printf ("%hhx\n", (unsigned char)testchar);

would be one option. IMO %x could be used here, but as mentioned above, some disagree.


NB. The wrong format specifier is used in printf ("%d\n", sizeof(char)); and the line following that. The specifier for size_t is %zu. So you could either use %zu, or cast the argument to int, or even better:

printf("1\n");

What happens is !!!!

1) unsigned char test = 49; // hex value 31 gets assigned

2) char testchar = (char) (test - 127); // 49-127 = -78 ie; 0xb2 (as unsigned),converting it to signed char results F padding before b2 to indicate it as negative

3) printf ("%x\n", testchar); //Since %x is a specifier for a 4-byte int (as @Don't You Worry Child said) ffffffb2, 4 byte output is obtained

So try as per @Don't You Worry Child said

I would have expected the following code to work:

It won't.

Ignoring the issues other people have pointed out with how you're printing the character, there is no guarantee in the standard that your code will work. Why?

Because char does not have to be signed. Whether char is signed or unsigned is implementation-dependent. Some implementations make char signed, others make it unsigned.

As such, there's no guarantee that (char) (test - 127) will produce a value that can be represented by char.

C++(14) does allow lossless conversion between unsigned char and char. The stadnard says (3.9.1/1):

For each value i of type unsigned char in the range 0 to 255 inclusive, there exists a value j of type char such that the result of an integral conversion (4.7) from i to char is j, and the result of an integral conversion from j to unsigned char is i.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top