我尝试使用变量a
和b
进行位算术。当我反转a
,其值为0xAF时,结果显示为8位数。
与显示为2位数字的其他数字不同。
我不知道为什么会这样,但是猜猜它与%x
显示方式和小端有关?
这是我的代码:
#include <stdio.h>
int main()
{
int a = 0xAF; // 10101111
int b = 0xB5; // 10110101
printf("%x \n", a & b); // a & b = 10100101
printf("%x \n", a | b); // a | b = 10111111
printf("%x \n", a ^ b); // a ^ b = 00011010
printf("%x \n", ~a); // ~a = 1....1 01010000
printf("%x \n", a << 2);// a << 2 = 1010111100
printf("%x \n", b >> 3); // b >> 3 = 00010110
return 0;
}
答案 0 :(得分:6)
考虑到您的int a
最有可能是32位,您的a
实际上是这样的:
int a = 0xAF; // 0000 0000 0000 0000 0000 0000 1010 1111
因此,如果您翻转所有位,那么
1111 1111 1111 1111 1111 1111 0101 0000
或者,以十六进制
0xFFFFFF50
这正是你得到的。其他只显示2位数字,因为在打印十六进制时省略了尾随零,而其他位操作实际上并没有改变任何前导零。
----感谢@ chqrlie为此---- 如果你真的只想看到结果的8位,你可以做
printf("%hhx \n", ~a); // ~a = 1....1 01010000 --> Output : 50
将打印值限制为unsigned char
(8位[在现代操作系统上,不保证,但非常可能用于您的目的])长度。
答案 1 :(得分:4)
这样的代码存在很多潜在的问题。
最重要的是,在进行按位操作时,绝不应使用像int
这样的有符号整数类型。因为您可能最终得到意外结果,或者如果在负值整数上使用<<
>>
之类的运算符,则最终可能会出现未定义/实现定义的行为错误。
所以第一步是确保你有一个无符号整数类型。优选uint32_t
或类似stdint.h
。
另一个相关的问题是,如果在表达式中使用小整数类型,例如uint8_t
,char
,short
,bool
等,那么它们将隐式获取提升为int
类型,这是一种签名类型。即使您使用unsigned char
或uint8_t
,也可以获得相同的效果。这是与按位运算符相关的许多致命错误的来源。
最后,当你需要明确表示类型时,printf
系列函数是危险的。虽然这些功能实际上具有零类型安全性,但它们同时采用某种特定类型。如果你给他们错误的类型,你会调用未定义的行为,程序可能会崩溃&amp;烧伤。此外,作为变量参数列表函数,它们还使用隐式的参数提升(默认参数提升),这也可能导致无法预料的错误。
&#34;奇怪&#34;输出您的体验是在签名类型上按位~
和printf
在为unsigned int
转换说明符提供时%x
的组合。
为了获得更确定的输出,你可以这样做:
#include <stdio.h>
#include <inttypes.h>
int main()
{
uint32_t a = 0xAF; // 10101111
uint32_t b = 0xB5; // 10110101
printf("%.8" PRIx32 "\n", a & b); // a & b = 10100101
printf("%.8" PRIx32 "\n", a | b); // a | b = 10111111
printf("%.8" PRIx32 "\n", a ^ b); // a ^ b = 00011010
printf("%.8" PRIx32 "\n", ~a); // ~a = 1....1 01010000
printf("%.8" PRIx32 "\n", a << 2); // a << 2 = 1010111100
printf("%.8" PRIx32 "\n", b >> 3); // b >> 3 = 00010110
return 0;
}