负数:如何将signed int中的符号位更改为0?

时间:2017-01-18 05:56:30

标签: c bit-manipulation

我在想这个世界是有效的,但事实并非如此:

int a = -500;
a = a << 1;
//printf("%d",a) gives me "-1000"

我的想法是左移会移除最左边的符号位,所以右移它作为无符号整数将保证它是一个逻辑移位而不是算术。为什么这不正确?

此外:

func sendRequest () {

    print("fire now----------------------------------------------")

    let parameters: Parameters = ["user": "001", "name": "josh"]

    print(parameters)
   let a = Alamofire.request("http://120.77.252.96:8388/", method: .get, parameters: parameters, encoding: URLEncoding.default).validate(statusCode: 200..<500).responseJSON(completionHandler: {responds in
        switch responds.result {
        case .success(let value):
            let json = JSON(value)
            print("JSON: \(json)")
        case .failure(let error):
            print(error)
        }}
    )
    print(a)

}

3 个答案:

答案 0 :(得分:7)

TL; DR:最简单的方法是使用abs中的<stdlib.h>函数。答案的其余部分涉及在计算机上表示负数。

负整数(几乎总是)在2's complement form中表示。 (见下面的注释)

获得数字否定的方法是:

  1. 获取整数的二进制表示(包括数据类型的前导零,除了将用作符号位的MSB)。
  2. 取以上号码的1's complement
  3. 1添加到1补码。
  4. 前缀sign bit
  5. 500为例,

    1. 采用500的二进制表示形式:_000 0001 1111 0100_是符号位的占位符。)
    2. 取1&#39; s-complement / inverse:_111 1110 0000 1011
    3. 1添加到1补码:_111 1110 0000 1011 + 1 = _111 1110 0000 1100。当您将符号位替换为零时,这与您获得的2147483148相同。
    4. 前缀0显示正数,1显示负数:1111 1110 0000 1100。 (这与上面的2147483148不同。你获得上述价值的原因是因为你获得了MSB)。
    5. 反转标志是一个类似的过程。如果您使用16位或32位数字导致您看到的大值,那么您将得到领先的数字。在每种情况下,LSB应该相同。

      注意:有些机器具有1的补码表示,但它们是少数。 2的补码通常是首选的,因为0具有相同的表示,即-00在2的补码表示法中表示为全零。

答案 1 :(得分:3)

左移负整数会调用未定义的行为,因此您无法执行此操作。如果您使用 a =(unsigned int)a&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 1; 。你得到500 = 0xFFFFFE0C ,左移1 = 0xFFFFFC18

&#xA;&#xA;

a =(unsigned int)a&gt;&gt; 1; 确实保证了逻辑移位,因此你得到 0x7FFFFE0C 。这是小数2147483148。

&#xA;&#xA;

但这是不必要的复杂。 更改符号位的最佳和最便携的方法是 a = -a 。任何其他代码或方法都值得怀疑。

&#xA;&#xA;

如果你坚持做点蠢事,你也可以做类似

&#xA; &#xA;
 (int32_t)a&amp; 〜(1u&lt;&lt; 31)&#xA;  
&#xA;&#xA;

这可以移植到32位系统,因为(int32_t)保证两个补码,但 1u&lt;&lt; 31 假设32位 int 类型。

&#xA;&#xA;

演示:

&#xA;&#xA;
  #include&lt; stdio.h&gt;&#xA; #include&lt; stdint.h&gt;&#xA;&#xA; int main(void)&#xA; {&#xA; int a = -500;&#xA; a =(unsigned int)a&lt;&lt; 1;&#XA; a =(unsigned int)a&gt;&gt; 1;&#XA; printf(“%。8X =%d \ n”,a,a);&#xA;&#xA; _Static_assert(sizeof(int)&gt; = 4,“Int必须至少为32位。”);&#xA; a = -500;&#xA; a =(int32_t)a&amp; 〜(1u <&lt; 31);&#xA; printf(“%。8X =%d \ n”,a,a);&#xA;&#xA;返回0;&#xA;}&#xA;  
&#xA;

答案 2 :(得分:-1)

当您放入“另外”部分时,在第一次左移1位后,DOES会按预期反映-1000。

问题在于你的转换为unsigned int。如上所述,负数表示为2的补码,意味着符号由最左位(最高有效位)确定。当转换为unsigned int时,该值不再表示符号,但会增加int可以采用的最大值。

假设32位整数,MSB用于表示-2 ^ 31(= -2147483648),现在在无符号整数中表示正2147483648,增加2 * 2147483648 = 4294967296.将其添加到原始值 - 1000,你得到4294966296.右移将此除以2,你到达2147483148。

希望这可能会有所帮助:(来自Print an int in binary representation using C的修改后的打印功能)

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;
}