unsigned char 的否定运算符

Negation operator on unsigned char

#include <stdio.h>
int main() {
    unsigned char a = 5;
    printf("%d\n",~a);
    printf("%d\n",a=~a);
    return 0;
}

根据这里接受的答案 ,在第一个 printf 中,a 应该提升为 int 并且输出应该是一个大的负数。但是第一个 printf 的输出是 -6。你能解释一下为什么输出是 -6 以及为什么在这种情况下 char 没有提升为 int 吗?

Can you please explain why the output is -6 and why the char is not promoted to int in this case?

不是真的,因为它 被提升为 int - 而且,作为 int ,反转所有位将(假设 two's-complement notation 且没有溢出)将正值 n 转换为负值,-(n+1).

对您的代码进行的这种修改可以证明正在发生的事情:

#include <stdio.h>
int main()
{
    int a = 5;
    printf("%d\n", ~a); // Prints -6
    printf("%d\n", a = (unsigned char)~a); // Prints 250 - lower 8 bits of the int
    return 0;
}

它正在升级并且 ~5 == -6 是二进制补码。假设二进制补码,一个小的正数的按位求反将产生一个小的负数。只有当被视为 unsigned 时,该数字才会显得很大,这就是链接答案中的 "%X" 所做的。

(顺便说一句,链接答案中的数字也应该在打印为 "%X" 之前转换为 unsigned,因为 printf 在技术上要求转换说明符和传递参数的类型)。

对于二进制补码内部表示,如果您有一个整数值x,则表达式

x + ~x + 1

等于0。

所以对于这个声明

unsigned char a = 5;

表达式 ~a 的操作数将被提升为 int 类型。

所以你会得到那个

~a + a + 1 = 0

~a + 5 + 1 = 0

因此表达式的值 ~a

~a = -5 -1 = -6

用二进制表示是这样的(前提是int类型占4个字节)

a ( = 5 ) = 00000000 00000000 00000000 00000101
~a        = 11111111 11111111 11111111 11111010

a + ~a    = 11111111 11111111 11111111 11111111

最后一个二进制值是-1在int类型中的表示。

在本次通话中

printf("%d\n",a=~a);

起初表达式 ~a 由于赋值而被截断为 unsigned char 类型的对象

a=~a

即表达式将有一个非负数。