unsigned char 和 char 异或运算

unsigned char and char XOR operation

有没有人可以帮我解释一下异或运算中unsigned char和char的区别是什么?

#include <stdio.h>

int main() {
    char a[2] = { 0x56, 0xa5 };  // a[0]  0101 0110   
                                 // a[1]  1010 0101 
    a[0] = a[0] ^ a[1];          // a[0]  1111 0011    f3   
    printf("%02x", a[0]);
    puts("");

    unsigned char b[2] = { 0x56, 0xa5 }; // b[0]  0101 0110
                                         // b[1]  1010 0101 
    b[0] = b[0] ^ b[1];                  // b[0]  1111 0011    f3   
    printf("%02x", b[0]);
    puts("");
}

结果:

fffffff3
f3
[Finished in 0.0s]

另一个例子:

#include <stdio.h>

int main() {
    char a[2] = { 0x01, 0x0a };

    a[0] = a[0] ^ a[1];          
    printf("%02x", a[0]);
    puts("");

    unsigned char b[2] = { 0x01, 0x0a };       

    b[0] = b[0] ^ b[1];             
    printf("%02x", b[0]);
    puts("");
}

结果:

0b
0b
[Finished in 0.0s]

(类型char是有符号的,sizeof(int)是4,每字节8位。)

a 的两个操作数被提升为 int,因为整数提升:

a[0]^a[1];   

因为a[1]是有符号类型,所以char这个数0xa5其实代表的是负值-91。值-91 在类型 int 中的表示是 0xffffffa5.

所以计算变为:

0x00000056 ^ 0xffffffa5

或十进制:

86 ^ -91

该操作的结果是:0xfffffff3

此计算的 unsigned char 版本没有此 'problem'。

第一种情况,你的代码

printf("%02x", a[0]);

char 值传递给可变函数 printfchar 值被提升为 int 类型并按原样传递。 a[0] 的值是 -13 因为 char 类型恰好在您的环境中默认签名,该值被促销保留为 int 并且 printf 将其接收为一个 int.

格式 %02x 需要一个 unsigned int 值。 printf 被传递了一个 int 值,一个不正确的类型调用未定义的行为。由于 intunsigned int 在您的平台上使用相同的参数传递约定,因此 -13 的这个负值被解释为具有相同位模式的 unsigned int,值 0xFFFFFFF3 因为您平台上的 int 有 32 位,负值以 2 的补码表示。 printf 生成的字符串是 fffffff3。 C 标准实际上并不保证此行为。

在第二个示例中,b[0] 是一个 unsigned char,值为 243 (0xf3)。将其提升为 int 会保留值,而传递给 printfint243。当 printf 被传递给 int 而不是 unsigned int 时,会调用相同的未定义行为。在您的特定情况下,由 printf 执行的转换产生相同的值,该值打印为十六进制,至少 2 位数字用前导 0 填充,给出 f3.

为避免这种歧义,您应该将操作数转换为 unsigned char:

printf("%02x", (unsigned)(unsigned char)a[0]);

或将其实际类型指定为unsigned char:

printf("%02hhx", (unsigned char)a[0]);