为什么 printf ("%d", ~a);当 a 等于 3 时显示 -4?

Why printf ("%d", ~a); displays -4 when a is equal to 3?

运行 以下程序显示 -4 而预期为 252:

unsigned char a=3;
printf ("%d", ~a);

为什么这个代码不显示 252?

我也根据建议的答案测试了以下内容:

printf ("%u", ~a);

显示:4294967292

printf ("%hu", ~a);

显示:65532

为什么 ~a 不是 return 一个 unsigned char 因为 一个 unsigned char?

我的问题不是我应该怎么做才能显示252?我的问题是为什么不显示252?

因为 ~a 是一个 int 而不是一个字符。如果要将其打印为 8 位无符号整数类型,请使用 "%hhu" 格式,如

printf("%hhu\n", ~a);

hh 前缀用于 8 位部分,u 用于未签名。

了解 integer promotions as well as how two's complement 表示负数的方法可能也会有所帮助。

来自 link 关于整数承诺:

integer promotions are applied ... to the operand of the unary bitwise operator ~

您的问题是以上讨论的混合问题。

除了,这里还有The Book1)的相关段落:

Unary arithmetic operators (§6.5.3.3/4)

The result of the ~ operator is the bitwise complement of its (promoted [ !! ] ) operand (that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set). The integer promotions are performed on the operand, and the result has the promoted type. If the promoted type is an unsigned type, the expression ~E is equivalent to the maximum value representable in that type minus E.

Arithmetic operands - Boolean, characters, and integers (§6.3.1.1):

  1. Every integer type has an integer conversion rank defined as follows:

    • No two signed integer types shall have the same rank, even if they have the same representation.
    • The rank of a signed integer type shall be greater than the rank of any signed integer type with less precision.
    • The rank of long long int shall be greater than the rank of long int, which shall be greater than the rank of int, which shall be greater than the rank of short int, which shall be greater than the rank of signed char.
    • The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type, if any.
    • The rank of any standard integer type shall be greater than the rank of any extended integer type with the same width.
    • The rank of char shall equal the rank of signed char and unsigned char.
    • The rank of _Bool shall be less than the rank of all other standard integer types.
    • The rank of any enumerated type shall equal the rank of the compatible integer type (see 6.7.2.2).
    • The rank of any extended signed integer type relative to another extended signed integer type with the same precision is implementation-defined, but still subject to the other rules for determining the integer conversion rank.
    • For all integer types T1, T2, and T3, if T1 has greater rank than T2 and T2 has greater rank than T3, then T1 has greater rank than T3.
  2. The following may be used in an expression wherever an int or unsigned int may be used:

    • An object or expression with an integer type whose integer conversion rank is less than or equal to the rank of int and unsigned int.
    • A bit-field of type _Bool, int, signed int, or unsigned int. If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.48) All other types are unchanged by the integer promotions.
  3. The integer promotions preserve value including sign. As discussed earlier, whether a "plain" char is treated as signed is implementation-defined.

48) The integer promotions are applied only: as part of the usual arithmetic conversions, to certain argument expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the shift operators, as specified by their respective subclauses.


您的问题:

Why ~a doesn't return an unsigned char since a is an unsigned char?

因为适用整数促销。

unsigned char a = 3;
printf ("%d", ~a);

a 是一个 unsigned char,一个范围可以用 int 表示的类型。所以 a 被提升为 int。假设 32 位宽 ints 和 two's complement:

310 = 0000 0000 0000 0000 0000 0000 0000 00112
~310 = 1111 1111 1111 1111 1111 1111 1111 11002

结果解释为 signed int 是负数,因为设置了最高有效位,即符号位。

转换为十进制:

1111 1111 1111 1111 1111 1111 1111 11002
¬ 0000 0000 0000 0000 0000 0000 0000 00112
+ 0000 0000 0000 0000 0000 0000 0000 00012
──────────────────────────────
0000 0000 0000 0000 0000 0000 0000 01002

01002 = 0 × 23 + 1 × 22 + 0 × 22 + 0 × 22
= 1 × 22
= 410
= −410(带原符号)

~> printf() 打印 -4.

要使用使用 "%d" 作为格式说明符的原始代码获得 252 的预期结果,需要进行一些转换:

unsigned char a = 3;
printf("%d\n", (int)((unsigned char) ~a));  // prints 252
//              ^^^   ^^^^^^^^^^^^^
//               |          cast the result of ~a back to unsigned char *)
//               |          to discard the bits > CHAR_BIT
//               cast the char back to int to agree with the format specifier 

*)感谢chux让我记住了char可以是signed!强制转换为(可能 signedchar 会给出错误的结果 -4.

要在不进行转换的情况下获得相同的结果,您可以使用长度修饰符 hh:

The fprintf function (§7.19.6.1/7)

The length modifiers and their meanings are:

hh  Specifies that a following d, i, o, u, x, or X conversion specifier applies to a signed char or unsigned char argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to signed char or unsigned char before printing); or that a following n conversion specifier applies to a pointer to a signed char argument.

[...]

unsigned char a = 3;
printf("%hhu\n", ~a);  // prints 252


你其他尝试的问题:

printf ("%u", ~a);

displays: 4294967292

printf ("%hu", ~a);

displays: 65532

因为 ~a 是一个 integer,它不是格式说明符 u

的正确类型

The fprintf function (§7.19.6.1/9):

If a conversion specification is invalid, the behavior is undefined.248) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.



1) ISO/IEC 9899/Cor3:2007 又名 C99:TR3 又名 C99

Why printf (“%d”, ~a); display -4 when a is equal to 3?
Why ~a doesn't return an unsigned char since a is an unsigned char?

unsigned char a=3;

因为 ~aint -4,而不是 unsigned char 252,因为 整数提升


~ 的应用导致 整数提升 a 进行按位补码之前.

If an int can represent all values of the original type ..., the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.

~3,给定常见的 2 的补码整数编码,是 -4。


在select 平台上,unsigned char, int, unsigned 都是相同的位宽。在那些特殊的平台上,~a 可能会采用类似 FFFFFFFC (4294967292) 的值,因为它被提升为 unsigned