Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 位旋转-与此程序混淆';s输出_C_Integer_Bit Shift_Bit Manipulation - Fatal编程技术网

C 位旋转-与此程序混淆';s输出

C 位旋转-与此程序混淆';s输出,c,integer,bit-shift,bit-manipulation,C,Integer,Bit Shift,Bit Manipulation,所以我在C语言中胡闹,我遇到了一个有趣的输出: int main() { int a = 0x00FF00FF; int b = 0xFFFF0000; int res = (~b & a); printf("%.8X\n", (res << 8) | (b >> 24)); } intmain() { INTA=0x00FF00FF; int b=0xFFFF0000; int res=(~b&a); printf(“%.8

所以我在C语言中胡闹,我遇到了一个有趣的输出:

int main()
{
    int a = 0x00FF00FF;
    int b = 0xFFFF0000;

    int res = (~b & a);

    printf("%.8X\n", (res << 8) | (b >> 24));
}
intmain()
{
INTA=0x00FF00FF;
int b=0xFFFF0000;
int res=(~b&a);
printf(“%.8X\n”,(分辨率>24));
}
该语句的输出为:

FFFFFFFF

我希望输出是

0000FFFF


但为什么不是呢?这里的位移位是否遗漏了什么?

TLDR:整数b是负数,因此当您将其向右移位时,最高位(即1)的值保持不变。因此,当您将b向右移动24个位置时,您将得到0xFFFFFF

详细解释:

假设在您的平台上,整数为32位或更长,有符号整数由2的补码表示,则分配给有符号整数变量的0xFFFF0000为负数。如果int大于32位,则0xFFFF0000将首先进行符号扩展,并且仍然是负数

将负数右移是本标准(C99/N1256,第6.5.7.5节)规定的实施方式:

E1>>E2的结果是E1右移位E2位位置。[…]如果E1 具有有符号类型和负值,结果值为 实现定义

这意味着一个特定的编译器可以选择在特定情况下发生的事情,但是应该在编译器手册中指出效果是什么

在许多处理器中往往有两组移位指令,一组是逻辑移位指令,一组是算术移位指令。逻辑右移将移位位并用零填充暴露位。算术右移(再次假设2的补码)将用最高有效位的相同位值填充暴露的位,从而得到与使用移位除以2一致的结果。(例如,-4>>1==0xFFFFFFFC>>1==0xFFFFFFFE==2。)

在您的例子中,编译器实现者似乎选择在应用于有符号整数时使用算术移位,因此将负值向右移位的结果仍然是负值。根据位模式0xFFFF0000>>24给出0xFFFFFFFF


除非您完全确定自己在做什么,否则最好只对无符号类型执行逐位操作,因为它们的内部表示可以被视为位的集合。您可能还希望通过在数字后面附加无符号后缀来确保在这种情况下使用的任何数值都是无符号的。

TLDR:整数b是负数,因此当您将其右移时,最高位(即1)的值保持不变。因此,当您将b向右移动24个位置时,您将得到0xFFFFFF

详细解释:

假设在您的平台上,整数为32位或更长,有符号整数由2的补码表示,则分配给有符号整数变量的0xFFFF0000为负数。如果int大于32位,则0xFFFF0000将首先进行符号扩展,并且仍然是负数

将负数右移是本标准(C99/N1256,第6.5.7.5节)规定的实施方式:

E1>>E2的结果是E1右移位E2位位置。[…]如果E1 具有有符号类型和负值,结果值为 实现定义

这意味着一个特定的编译器可以选择在特定情况下发生的事情,但是应该在编译器手册中指出效果是什么

在许多处理器中往往有两组移位指令,一组是逻辑移位指令,一组是算术移位指令。逻辑右移将移位位并用零填充暴露位。算术右移(再次假设2的补码)将用最高有效位的相同位值填充暴露的位,从而得到与使用移位除以2一致的结果。(例如,-4>>1==0xFFFFFFFC>>1==0xFFFFFFFE==2。)

在您的例子中,编译器实现者似乎选择在应用于有符号整数时使用算术移位,因此将负值向右移位的结果仍然是负值。根据位模式0xFFFF0000>>24给出0xFFFFFFFF


除非您完全确定自己在做什么,否则最好只对无符号类型执行逐位操作,因为它们的内部表示可以被视为位的集合。您可能还希望通过在数字后面添加无符号后缀来确保在这种情况下使用的任何数值都是无符号的。

黄金法则:永远不要将有符号数字与位运算符混合使用

将所有整数更改为无符号整数。作为预防措施,将所有文本也更改为unsigned

#include <stdint.h>

uint32_t a = 0x00FF00FFu;
uint32_t b = 0xFFFF0000u;

uint32_t res = (~b & a);
#包括
uint32_t a=0x00FF00FFu;
uint32_t b=0xFFFF0000u;
uint32_t res=(~b&a);

黄金法则:永远不要将有符号数字与位运算符混合使用

将所有整数更改为无符号整数。作为预防措施,将所有文本也更改为unsigned

#include <stdint.h>

uint32_t a = 0x00FF00FFu;
uint32_t b = 0xFFFF0000u;

uint32_t res = (~b & a);
#包括
uint32_t a=0x00FF00FFu;
uint32_t b=0xFFFF0000u;
uint32_t res=(~b&a);

右移位负值(如
b
)可以用两种不同的方式定义:逻辑移位,在左边用零填充值(在移位非零值时产生一个正数),算术移位,用一填充值(总是产生一个负数)。C中使用的定义是实现定义的,并且编译器显然使用算术移位,因此
b>>24
0xFFFFFFFF

右移负值(如
b
)可以用两种不同的方式定义:逻辑移位,它在左边用零填充值(移动非零值时产生一个正数)和算术移位,用1填充值(总是产生一个负数)