简体   繁体   中英

C typecasting from a signed char to int type

In the below snippet, shouldn't the output be 1? Why am I getting output as -1 and 4294967295? What I understand is, the variable, c, here is of signed type, so shouldn't its value be 1?

char c=0xff;
printf("%d %u",c,c);

c is of signed type. a char is 8 bits. So you have an 8 bit signed quantity, with all bits 1. On a twos complement machine, that evaluates to -1.

Some compilers will warn you when you do that sort of thing. If you're using gcc/clang, switch on all the warnings.

Pedant note: On some machines it could have the value 255, should the compiler treat 'char' as unsigned.

You're getting the correct answer.

The %u format specifier indicates that the value will be an unsigned int . The compiler automatically promotes your 8-bit char to a 32-bit int . However you have to remember that char is a signed type. So a value of 0xff is in fact -1.

When the casting from char to int occurs, the value is still -1, but the it's the 32-bit representation which in binary is 11111111 11111111 11111111 11111111 or in hex 0xffffffff

When that is interpreted as an unsigned integer, all of the bits are obviously preserved because the length is the same, but now it's handled as an unsigned quantity.

0xffffffff = 4294967295 (unsigned)
0xffffffff = -1 (signed)

There are three character types in C, char , signed char , and unsigned char . Plain char has the same representation as either signed char or unsigned char ; the choice is implementation-defined. It appears that plain char is signed in your implementation.

All three types have the same size, which is probably 8 bits ( CHAR_BIT , defined in <limits.h> , specifies the number of bits in a byte). I'll assume 8 bits.

char c=0xff;

Assuming plain char is signed, the value 0xff ( 255 ) is outside the range of type char . Since you can't store the value 255 in a char object, the value is implicitly converted. The result of this conversion is implementation-defined, but is very likely to be -1 .

Keep this carefully in mind: 0xff is simply another way to write 255 , and 0xff and -1 are two distinct values. You cannot store the value 255 in a char object; its value is -1 . Integer constants, whether they're decimal, hexadecimal, or octal, specify values, not representations.

If you really want a one-byte object with the value 0xff , define it as an unsigned char , not as a char .

printf("%d %u",c,c);

When a value of an integer type narrower than int is passed to printf (or to any variadic function), it's promoted to int if that type can hold the type's entire range of values, or to unsigned int if it can't. For type char , it's almost certainly promoted to int . So this call is equivalent to:

printf("%d %u", -1, -1);

The output for the "%d" format is obvious. The output for "%u" is less obvious. "%u" tells printf that the corresponding argument is of type unsigned int , but you've passed it a value of type int . What probably happens is that the representation of the int value is treated as if it were of type unsigned int , most likely yielding UINT_MAX , which happens to be 4294967295 on your system. If you really want to do that, you should convert the value to type unsigned int . This:

printf("%d %u", -1, (unsigned int)-1);

is well defined.

Your two lines of code are playing a lot of games with various types, treating values of one type as if they were of another type, and doing implicit conversions that might yield results that are implementation-defined and/or depend on the choices your compiler happens to make.

Whatever you're trying to do, there's undoubtedly a cleaner way to do it (unless you're just trying to see what your implementation does with this particular code).

Let us start with the assumption using OP's "c, here is of signed type"

char c=0xff;  // Implementation defined behavior.

0xff is a hexadecimal constant with the value of 255 and type of int .

... the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised. §6.3.1.4 3

So right off, the value of c is implementation defined (ID). Let us assume the common ID behavior of 8-bit wrap-around, so c --> -1.


A signed char will be promoted to int as part of a variadic argument to printf("%d %u",c,c); is the same as printf("%d %u",-1, -1); . Printing the -1 with "%d" is not an issue and "-1" is printed.

Printing an int -1 with "%x" is undefined behavior (UB) as it is a mis-matched specifier/type and does not fall under the exception of being representable in both types. The common UB is to print the value as if it was converted to unsigned before being passed. When UINT_MAX == 4294967295 (4-bytes) that prints the value as -1 + (UINT_MAX + 1) or "4294967295"`.


So with ID and UB, you get a result, but robust code would be re-written to depend on neither.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM