Reputation: 836
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?
Upvotes: 5
Views: 742
Reputation: 473427
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 typechar
such that the result of an integral conversion (4.7) from i tochar
is j, and the result of an integral conversion from j tounsigned char
is i.
Upvotes: 0
Reputation: 1644
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
Upvotes: 2
Reputation: 141574
%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 int
s 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");
Upvotes: 2
Reputation: 6116
%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
.
Upvotes: 5
Reputation: 229108
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?
Upvotes: 5