有没有人可以帮我解释XOR操作中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]
答案 0 :(得分:1)
在第一种情况下,您的代码
printf("%02x", a[0]);
将char
值传递给可变参数函数printf
。 char
值将提升为int
类型并按原样传递。 a[0]
的值为-13
,因为您的环境默认情况下会对char
类型进行签名,该值会被促销保留为int
,而printf会将其作为int
接收%02x
。
格式unsigned int
需要printf
值。 int
传递了int
值,这是一种调用未定义行为的错误类型。由于unsigned int
和-13
在您的平台上使用相同的参数传递约定,因此unsigned int
的负值被解释为具有相同位模式的0xFFFFFFF3
,值为{{ 1}}因为平台上的int
有32位,负值用2s补码表示。 printf生成的字符串为fffffff3
。 C标准实际上并未保证此行为。
在第二个示例中,b[0]
是unsigned char
,其值为243
(0xf3
)。其促销至int
会保留价值,而传递给int
的{{1}}则为printf
。调用相同的未定义行为,因为243
传递printf
而不是int
。在您的特定情况下,由unsigned int
执行的转化会产生相同的值,该值打印为十六进制,至少2位数字用前导printf
填充0
。
为避免这种歧义,您应该将操作数强制转换为f3
:
unsigned char
或者将其实际类型指定为printf("%02x", (unsigned)(unsigned char)a[0]);
:
unsigned char
答案 1 :(得分:0)
(类型char
已签名,sizeof(int)为4,每字节8位。)
由于整数提升,a
的两个操作数都被提升为int
:
a[0]^a[1];
由于a[1]
是签名类型char
,因此数字0xa5
实际上代表负值-91。类型int
中-91值的表示形式为0xffffffa5
。
所以计算结果如下:
0x00000056 ^ 0xffffffa5
或十进制:
86 ^ -91
该操作的结果是:0xfffffff3
此计算的unsigned char版本没有这个问题&#39;。