C 负数:如何将有符号整数中的符号位更改为0?
我认为这个世界是可行的,但事实并非如此:C 负数:如何将有符号整数中的符号位更改为0?,c,bit-manipulation,C,Bit Manipulation,我认为这个世界是可行的,但事实并非如此: int a = -500; a = a << 1; a = (unsigned int)a >> 1; //printf("%d",a) gives me "2147483148" inta=-500; a=a>1; //printf(“%d”,a)给了我“2147483148” 我的想法是左移位将删除最左边的符号位,因此将其作为无符号int进行右移位将保证它是逻辑移位而不是算术移位。为什么这是不正确的 此外: inta=-5
int a = -500;
a = a << 1;
a = (unsigned int)a >> 1;
//printf("%d",a) gives me "2147483148"
inta=-500;
a=a>1;
//printf(“%d”,a)给了我“2147483148”
我的想法是左移位将删除最左边的符号位,因此将其作为无符号int进行右移位将保证它是逻辑移位而不是算术移位。为什么这是不正确的
此外:
inta=-500;
a=aTL;DR:最简单的方法是使用
中的abs
功能。答案的其余部分涉及在计算机上表示负数
负整数(几乎总是)表示为。(见下文注释)
获取数字负数的方法是:
取整数的二进制表示形式(包括数据类型的前导零,但用作符号位的MSB除外)
以上面的数字为例
将1
添加到1的补码中
前缀a
以500
为例
以500
的二进制表示形式为例:\u 000 0001 1111 0100
(\u
是符号位的占位符)
取其1的补/反:\u 111 1110 0000 1011
将1
添加到1的补码中:\u 111 1110 0000 1011+1=\u 111 1110 0000 1100
。这与将符号位替换为零时获得的2147483148
相同
前缀0
表示正数,前缀1
表示负数:1111110 0000 1100
。(这将不同于上面的2147483148
。获取上述值的原因是您对MSB进行了核弹处理)
反转符号也是一个类似的过程。如果您使用16位或32位数字引导您看到的大值,则会得到前导数字。在每种情况下,LSB应相同
注意:有些机器使用1的补码表示,但它们是少数。2的补码通常是首选的,因为0
具有相同的表示,即-0
和0
在2的补码表示法中表示为全零。左移负整数调用未定义的行为,所以不能这样做。如果您在“还”部分中输入了a=(unsigned int)a,则可以使用代码,在第一次左移1位后,a确实会像预期的那样反映-1000
问题在于对unsigned int的强制转换。如上所述,负数表示为2的补码,这意味着符号由最左边的位(最高有效位)确定。当强制转换为无符号整数时,该值不再表示符号,而是增加整数可以接受的最大值
假设32位整数,MSB过去表示-2^31(=2147483648),现在表示无符号整数中的正2147483648,增加2*2147483648=4294967296。将此值与原始值-1000相加,得到4294966296。右班除以2,到达2147483148
希望这可能会有所帮助:(修改打印功能自)
void int2bin(int a,char*buffer,int buf_size){
缓冲区+=(buf_大小-1);
对于(int i=buf_size-1;i>=0;i--){
*缓冲区--=(a&1)+“0”;
a>>=1;
}
}
int main(){
int检验=-500;
int bufSize=sizeof(int)*8+1;
字符buf[bufSize];
buf[bufSize-1]='\0';
int2bin(测试,buf,bufSize-1);
printf(“%i(%u):%s\n”,test,(unsigned int)test,buf);
//打印:-500(4294966796):11111111111111 00000 1100
test=test它确实有效,它将符号设置为0。但可能不是您想要的方式。如果您想用bitmath实现abs
,它比这要复杂一些。公平地说,将标准abs
用于MIN_INT有点危险。不是固有的,而是溢出和UB-yada-yada..您可以只做一个无符号的abs
<代码> >(x<0)返回(未签名)x;否则返回(未签名)x;< /C> > C和C++,<代码> A,因为您要求更改<代码>符号>代码>位(x86 ASM操作码:代码>未/代码>),并且不将负数转换成正数(x86 ASM操作码:<代码> NEG < /代码>)。这是两个不同的东西。下面的答案解释了这一点,并且是正确的。@Hurkyl有区别吗?在任何情况下,如果有区别,它在这里都不可见。在您的示例中,左移31是UB,因为2^31在int32_t中不可表示。编辑:假设int与int32_t具有相同的表示。@2501lu
后缀应该是什么没有必要,因为有断言。对,我忘记了。但是,int可能有两个填充字节。:-)sizeof不计算范围。你应该使用int\u MAX>=2^31-1。lu避免了所有这些。我正在处理gnss坐标,需要我找出它是0还是-0?我如何识别-0?
int a = -500;
a = a << 1;
//printf("%d",a) gives me "-1000"
(int32_t)a & ~(1u << 31)
#include <stdio.h>
#include <stdint.h>
int main (void)
{
int a = -500;
a = (unsigned int)a << 1;
a = (unsigned int)a >> 1;
printf("%.8X = %d\n", a, a);
_Static_assert(sizeof(int)>=4, "Int must be at least 32 bits.");
a = -500;
a = (int32_t)a & ~(1u << 31);
printf("%.8X = %d\n", a, a);
return 0;
}
void int2bin(int a, char *buffer, int buf_size) {
buffer += (buf_size - 1);
for (int i = buf_size-1; i >= 0; i--) {
*buffer-- = (a & 1) + '0';
a >>= 1;
}
}
int main() {
int test = -500;
int bufSize = sizeof(int)*8 + 1;
char buf[bufSize];
buf[bufSize-1] = '\0';
int2bin(test, buf, bufSize-1);
printf("%i (%u): %s\n", test, (unsigned int)test, buf);
//Prints: -500 (4294966796): 11111111111111111111111000001100
test = test << 1;
int2bin(test, buf, bufSize-1);
printf("%i (%u): %s\n", test, (unsigned int)test, buf);
//Prints: -1000 (4294966296): 11111111111111111111110000011000
test = 500;
int2bin(test, buf, bufSize-1);
printf("%i (%u): %s\n", test, (unsigned int)test, buf);
//Prints: 500 (500): 00000000000000000000000111110100
return 0;
}