简体   繁体   English

为什么使用 %u 时我的 char 的二进制值会发生变化?

[英]Why does the binary value of my char change when using %u?

char a = 0b11111111;

printf("%u", a);

We are storing in a signed char (in gcc default char is signed) 1111 1111, meaning -1.我们存储在一个带符号的字符中(在 gcc 默认字符是有符号的)1111 1111,意思是 -1。 But we print with %u, so printf should see 0000 0000 0000 0000 0000 0000 1111 1111.但是我们使用 %u 打印,所以 printf应该看到 0000 0000 0000 0000 0000 0000 1111 1111。

This number, with two's complement or without - is 255. So why am I getting (2^32 - 1)?这个数字,有或没有补码 - 是 255。那么为什么我得到 (2^32 - 1)? Seems like instead of putting leading zeros (like I expected) the program put leading ones.似乎程序没有放置前导零(就像我预期的那样),而是放置了前导零。

There are multiple problems in your example:您的示例中有多个问题:

  • char a = 0b11111111; uses an extension for binary literals.使用二进制文字的扩展。

  • char a = 0b11111111; has implementation defined behavior if char is signed and CHAR_MAX < 255 .如果char已签名且CHAR_MAX < 255 ,则具有实现定义的行为。

  • printf("%u", a) has undefined behavior because the char value a is promoted to int when passed to printf , which expects an unsigned int for the format %u . printf("%u", a)具有未定义的行为,因为chara在传递给printf时被提升为int ,它需要格式为%uunsigned int

    One exception is the rare architectures (mostly DSPs) where char is unsigned by default and has the same size as unsigned int .一个例外是罕见的架构(主要是 DSP),其中char默认是无符号的,并且具有与unsigned int相同的大小。 But then char is not signed and your example does not pose a problem.但是然后char没有签名,您的示例不会造成问题。

If you want to print the exact value of type unsigned char , you should use %hhu , or use %u and cast the argument as (unsigned char)如果要打印unsigned char类型的确切值,则应使用%hhu ,或使用%u并将参数转换为(unsigned char)

As @Lundin stated conversion rules apply正如@Lundin 所述,转换规则适用

to print correctly:正确打印:

    printf("%hhu\n", (unsigned char)a);
    printf("%u\n", (unsigned char)a);
    printf("%"PRIu8"\n", (uint8_t)a);

First of all, char may be signed or unsigned depending on compiler and is therefore unsuitable for storying raw binary, see Is char signed or unsigned by default?首先, char可能是有符号或无符号的,具体取决于编译器,因此不适合记录原始二进制文件,请参阅Is char signed or unsigned by default? . .

In your case it is apparently signed, in which case the value 0b11111111 = 255 won't fit.在您的情况下,它显然已签名,在这种情况下,值 0b11111111 = 255 将不适合。 Upon assignment, 255 will get implicitly converted to the signed char in a compiler-specific way.分配后, 255 将以特定于编译器的方式隐式转换为有signed char Very likely as the 2's complement number -1 .很可能作为 2 的补码-1

Now as you pass any small integer type to printf , they get implicitly promoted by an oddball rule called default argument promotions , which applies to all variable number of argument functions.现在,当您将任何小的 integer 类型传递给printf时,它们会被称为默认参数提升的奇怪规则隐式提升,该规则适用于所有可变数量的参数函数。 This rule goes:这条规则是:

the integer promotions are performed on each argument, and arguments that have type float are promoted to double对每个参数执行 integer 提升,并且具有浮点类型的 arguments 提升为双精度

For the meaning of "small integer type" and integer promotion, please check Implicit type promotion rules .关于“小 integer 类型”和 integer 提升的含义,请查看隐式类型提升规则

This means that what's passed to printf is an int , still with value -1 but sign extended .这意味着传递给printf的是一个int ,其值仍为 -1 但符号为 extended Since int is likely something like 4 byte, it now contains the raw binary 0xFFFFFFFF instead of just 0xFF.由于int可能类似于 4 字节,它现在包含原始二进制 0xFFFFFFFF 而不仅仅是 0xFF。 Which is still the decimal number -1 , just a larger type.这仍然是十进制数-1 ,只是一个更大的类型。

Then finally you tell printf to print it as unsigned int , so it gets converted by printf to the unsigned representation of 0xFFFFFFFF .然后最后告诉printf将其打印为unsigned int ,因此它由printf转换为0xFFFFFFFF的无符号表示。 This is a well-defined conversion (C17 6.3.1.3):这是一个定义明确的转换(C17 6.3.1.3):

Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.否则,如果新类型是无符号的,则在新类型可以表示的最大值的基础上重复加减一,直到该值在新类型的范围内。

And you will end up with 2^32 - 1 = 4294967295 on a 32 bit int computer.在 32 位int计算机上,您最终会得到 2^32 - 1 = 4294967295。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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