代码之家  ›  专栏  ›  技术社区  ›  hookenz

C/C++中的数字重构

c++
  •  2
  • hookenz  · 技术社区  · 14 年前

    我有一个字节流,它是从套接字(little endian)读入的。 有人能告诉我为什么只有最后一种方法给出正确答案吗? 我怀疑这和那个带钻头有关,但不确定。我总是发现 以十六进制格式打印二进制数据。

    例如

    printf("%02X", data);
    

    它有时会打印出前面有0xff的有趣值。解决的办法似乎是 你应该这样做。当数据也是char数据类型时,这种情况仍然偶尔发生:

    printf("%02X", data & 0xff);
    

    其中bytes是我从套接字读取的字节流。

    int main(int argc, char* argv[])
    {
        union {
            unsigned int num;
            char bytes[4];
        } x;
    
        x.num = 500;
        printf("x.num=%u\n", x.num);
    
        unsigned int method1 = x.bytes[0] | (x.bytes[1] << 8) | (x.bytes[2] << 16) | (x.bytes[3] << 24);
        printf("method1 = %u\n", method1);
    
        unsigned int method2 = x.bytes[0] + (x.bytes[1] << 8) + (x.bytes[2] << 16) + (x.bytes[3] << 24);
        printf("method2 = %u\n", method2);
    
        unsigned int method3 = (x.bytes[0] & 0xff | (x.bytes[1] & 0xff) << 8 
                                | (x.bytes[2] & 0xff) << 16 | (x.bytes[3] & 0xff) << 24);
        printf("method3 = %u\n", method3);
    
        return 0;
    }
    

    输出:

    x.num=500
    method1 = 4294967284
    method2 = 244
    method3 = 500
    

    只有最后的摘录是正确的。 我建立数字的方法是最理想的吗?我也试过 memcpy 一个变量,但这是不可靠的。

    3 回复  |  直到 14 年前
        1
  •  4
  •   deinst    14 年前

    当有符号数据类型转换为更高的数据类型时,最高有效位用作符号位。你应该有 unsigned char 在你的工会里。在您的例子中,500=256+244=0x1f4,字节244具有最高有效位集,因此升级时变为0xfffff4。

        2
  •  1
  •   Alex Martelli    14 年前

    为什么不用 unsigned char bytes[4] union ? 如果没有签名规范,您就不知道 char s是有符号的或无符号的(取决于平台和编译器),所以在它们上面的算法给出特殊的结果也就不足为奇了。

    这个 0xFF

    根据经验,什么时候 用于表示“用于进一步处理或显示目的的字节”,我建议始终使用 unsigned char 确切地说,我不记得上一次是什么时候我真的想要一个 签署

        3
  •  0
  •   paxdiablo    14 年前

    在一个小小的endian建筑中 500 ( 256 + 244

    +-----------+-----------+-----------+-----------+
    | 244(0xf4) |   1(0x01) |   0(0x00) |   0(0x00) |
    +-----------+-----------+-----------+-----------+
    

    因为你用的是 char 就其本身而言,C标准没有指定它是有符号的还是无符号的(它是由实现定义的)。在你的情况下,它似乎是签署。

    旁白:符号扩展发生在2的补码编码中,当您将“瘦”数据值加载到更宽的数据值中时。如果细数的高位为1(表示负数),则扩展到更宽类型中的所有高位。这样做的原因是为了保留数字的性质。例如,8位中的-12是 0xf4 ,在16位是 0xfff4 0xfffffffffffffffffffffffffffffff4 .

    这意味着 244 ( -12 0xfffffff4 . 那很可能会把你的计划搞砸 | + 解决方案相当糟糕。

    x0       0xfffffff4  
    x1<<8    0x00000100
    x2<<16   0x00000000
    x3<<24   0x00000000
    

    方法1使用 | 所以你最终 0xFFFFF4 (x1中的另一位已经设置在x0中,因此它不受影响,并且x2/x3都是零)这是 4294967284 unsigned int .

    0x1000000f4 当然,它会包装,丢弃高字节,留给您 或者244。

    在方法3中,符号扩展仍然发生,但是 & 0xff . 就是这样 & 反转标志延伸效果并使您的 回到 0xf4型

    正如其他人已经提到的,使用 unsigned char 明确地。这将防止升级为更大的整数类型时发生符号扩展。