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
值传递给可变函数 printf
。 char
值被提升为 int
类型并按原样传递。 a[0]
的值是 -13
因为 char
类型恰好在您的环境中默认签名,该值被促销保留为 int
并且 printf 将其接收为一个 int
.
格式 %02x
需要一个 unsigned int
值。 printf
被传递了一个 int
值,一个不正确的类型调用未定义的行为。由于 int
和 unsigned int
在您的平台上使用相同的参数传递约定,因此 -13
的这个负值被解释为具有相同位模式的 unsigned int
,值 0xFFFFFFF3
因为您平台上的 int
有 32 位,负值以 2 的补码表示。 printf 生成的字符串是 fffffff3
。 C 标准实际上并不保证此行为。
在第二个示例中,b[0]
是一个 unsigned char
,值为 243
(0xf3
)。将其提升为 int
会保留值,而传递给 printf
的 int
为 243
。当 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]);
有没有人可以帮我解释一下异或运算中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
值传递给可变函数 printf
。 char
值被提升为 int
类型并按原样传递。 a[0]
的值是 -13
因为 char
类型恰好在您的环境中默认签名,该值被促销保留为 int
并且 printf 将其接收为一个 int
.
格式 %02x
需要一个 unsigned int
值。 printf
被传递了一个 int
值,一个不正确的类型调用未定义的行为。由于 int
和 unsigned int
在您的平台上使用相同的参数传递约定,因此 -13
的这个负值被解释为具有相同位模式的 unsigned int
,值 0xFFFFFFF3
因为您平台上的 int
有 32 位,负值以 2 的补码表示。 printf 生成的字符串是 fffffff3
。 C 标准实际上并不保证此行为。
在第二个示例中,b[0]
是一个 unsigned char
,值为 243
(0xf3
)。将其提升为 int
会保留值,而传递给 printf
的 int
为 243
。当 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]);