You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何两段提取4位二进制位的代码表现不同?(正负整数转十六进制)

正负整数转十六进制:两种4位提取写法的差异原因

我们需要实现正负整数转十六进制的功能,核心逻辑是从整数中按4位一组提取二进制位并转换为十六进制字符。以下是两种提取4位二进制位的写法,写法2能正常处理正负整数,但写法1结果异常,具体原因如下:

原代码及两种写法对比

完整转十六进制代码

string toHex(int num) {
    string ans = "";

    // 按4位一组遍历整数
    for (int i = 28; i >= 0; i -= 4) 
    {
        // 存在问题的写法1
        /***********************************************/
        // 提取从第i位开始的4位二进制
        int number_before = (num  & (15 << i));
        number_before = (number_before >> i) ;
        /***********************************************/

        // 转换为十六进制字符并追加到结果
        if(number_before == 0 && ans.size() == 0) continue;
        else if (number_before < 10) {
            ans += (char)(number_before + '0');  // 0-9转'0'-'9'
        } else {
            ans += (char)(number_before - 10 + 'A');  // 10-15转'A'-'F'
        }
    }

    return ans;
}

两种提取写法

写法1(异常)

int number_before = (num  & (15 << i));
number_before = (number_before >> i) ;

写法2(正常)

int number_before = ((num>> i) & 15 );

问题原因分析

核心问题出在有符号整数的算术右移特性和15 << i的溢出行为:

  1. 写法1的问题拆解

    • 第一步num & (15 << i):当i=28时,15(二进制0xF)左移28位后,对于32位有符号int来说,结果的最高位(符号位)会被置1,变成一个负数(比如0xF0000000,对应十进制-16777216)。如果原num是负数,按位与后得到的number_before也是一个高位为1的负数。
    • 第二步number_before >> i:C++中,有符号整数的右移是算术右移——负数右移时会在高位补1而不是0。比如0xF0000000右移28位后,会变成0xFFFFFFFF(即十进制-1),而不是我们期望的0xF,这直接导致后续转换的十六进制字符错误。
  2. 写法2的正确性逻辑

    • 先执行num >> i:负数做算术右移时会补符号位,但紧接着我们和15(二进制0b1111)做按位与操作。15的高位全为0,会把右移后补的所有1全部清零,只保留低4位的有效数值,最终得到的就是我们需要的0-15范围内的正确值,后续转换自然正常。

内容的提问来源于stack exchange,提问作者Satyam Mittal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 04:40:08