我对C中的位移做了一个小测试,所有的位移0,8,16位都没问题,我理解发生了什么。
但32位右移或左移对我来说并不清楚,我正在测试的变量是32位长。
然后,我改变了32位变量,这些变量将保持移位结果,但是32位左右移位是相同的!
这是我的代码:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
int main() {
uint32_t code = 0xCDBAFFEE;
uint64_t bit32R = code >> 32;
uint16_t bit16R = code >> 16;
uint8_t bit8R = code >> 8;
uint8_t bit0R = code >> 0;
uint64_t bit32L = code << 32;
uint16_t bit16L = code << 16;
uint8_t bit8L = code << 8;
uint8_t bit0L = code << 0;
printf("Right shift:\nbit32R %.16x\nbit16R %x\nbit8R %x\nbit0R %x\n\n",
bit32R, bit16R, bit8R, bit0R);
printf("Left shift:\nbit32L %.16x\nbit16L %x\nbit8L %x\nbit0L %x\n\n",
bit32L, bit16L, bit8L, bit0L);
}
这是我得到的结果:
Right shift:
bit32R 00000000cdbaffee
bit16R 0
bit8R cdba
bit0R ff
Left shift:
bit32L 00000000cdbaffee
bit16L 0
bit8L 0
bit0L 0
Process returned 61 (0x3D) execution time : 0.041 s
Press any key to continue.
答案 0 :(得分:6)
将整数右移一个等于或大于其大小的位数是不确定的行为。
C11 6.5.7按位移位运算符
语法
shift-expression: additive-expression shift-expression << additive-expression shift-expression >> additive-expression
约束
每个操作数都应具有整数类型。
语义
对每个操作数执行整数提升。结果的类型是提升的左操作数的类型。如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。
E1 << E2
的结果是E1
左移E2
位位置;腾出的位用零填充。如果E1
具有无符号类型,则结果的值为E1
×2 E2 ,比结果类型中可表示的最大值减少一个模数。如果E1
具有带符号类型和非负值,并且E1
×2 E2 在结果类型中可表示,那么这就是结果值;否则,行为未定义。
E1 >> E2
的结果是E1
右移E2
位位置。如果E1
具有无符号类型或者E1具有有符号类型和非负值,则结果的值是E1
/ 2 E2 的商的整数部分。如果E1
具有签名类型和负值,则结果值是实现定义的。
平台上int
的大小似乎最多为32位,因此bit32R
和bit32L
的初始化程序具有未定义的行为。
应写入64位表达式:
uint64_t bit32R = (uint64_t)code >> 32;
和
uint64_t bit32L = (uint64_t)code << 32;
此外,printf
中使用的格式对于传递的参数不正确(除非int
具有64位,这将产生不同的输出)。
您的编译器似乎不完全符合C99,您应该在函数return 0;
的主体末尾添加最后的main()
语句。
以下是更正后的版本:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
int main(void) {
uint32_t code = 0xCDBAFFEE;
uint64_t bit32R = (uint64_t)code >> 32;
uint16_t bit16R = code >> 16;
uint8_t bit8R = code >> 8;
uint8_t bit0R = code >> 0;
uint64_t bit32L = (uint64_t)code << 32;
uint16_t bit16L = code << 16;
uint8_t bit8L = code << 8;
uint8_t bit0L = code << 0;
printf("Right shift:\n"
"bit32R %.16"PRIx64"\n"
"bit16R %"PRIx16"\n"
"bit8R %"PRIx8"\n"
"bit0R %"PRIx8"\n\n",
bit32R, bit16R, bit8R, bit0R);
printf("Left shift:\n"
"bit32L %.16"PRIx64"\n"
"bit16L %"PRIx16"\n"
"bit8L %"PRIx8"\n"
"bit0L %"PRIx8"\n\n",
bit32L, bit16L, bit8L, bit0L);
return 0;
}
输出结果为:
Right shift:
bit32R 0000000000000000
bit16R cdba
bit8R ff
bit0R ee
Left shift:
bit32L cdbaffee00000000
bit16L 0
bit8L 0
bit0L ee
这可能不是您所期望的,因为变量的类型有些不一致。
答案 1 :(得分:1)
一个问题是您使用%x
打印64位整数。您应该为每个变量使用正确的格式说明符。有这方面的宏:
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
// ...
printf("64 bit result: %" PRIx64 "\n", bit32R);
printf("16 bit result: %" PRIx16 "\n", bit16R);
printf("8 bit result: %" PRIx8 "\n", bit8R);
可以找到更多信息here。
答案 2 :(得分:0)
你没有在那里进行64位左移,因为代码是uint32_t,所以编译器使用32位版本的运算符。此外,您应该告诉print使用long long(与uint64_t相同)
#include <cstdint>
#include <stdio.h>
int main ()
{
uint32_t code = 0xCDBAFFEE;
uint64_t bit32R=((uint64_t)code)>>32;
uint16_t bit16R=code>>16;
uint8_t bit8R=code>>8;
uint8_t bit0R=code>>0;
uint64_t bit32L=((uint64_t)code)<<32;
uint16_t bit16L=code<<16;
uint8_t bit8L=code<<8;
uint8_t bit0L=code<<0;
printf("Right shift:\nbit32R %llx\nbit16R %x\nbit8R %x\nbit0R %x\n\n", bit32R,bit16R,bit8R,bit0R);
printf("Leftt shift:\nbit32L %llx\nbit16L %x\nbit8L %x\nbit0L %x", bit32L,bit16L,bit8L,bit0L);
}
结果是:
Right shift:
bit32R 0
bit16R cdba
bit8R ff
bit0R ee
Leftt shift:
bit32L cdbaffee00000000
bit16L 0
bit8L 0
bit0L ee
如果你有C99兼容的编译器,你应该使用inttypes.h中定义的宏,遗憾的是某些平台没有这些定义。 printf的格式描述符与平台有关。