当前位置: 首页 > 知识库问答 >
问题:

将2字节转换为有符号16位整数的正确方法是什么?

阳英朗
2023-03-14

在这个答复中, zwol提出了这样的主张:

将两个字节的数据从外部源转换为16位有符号整数的正确方法是使用以下帮助函数:

#include <stdint.h>

int16_t be16_to_cpu_signed(const uint8_t data[static 2]) {
    uint32_t val = (((uint32_t)data[0]) << 8) | 
                   (((uint32_t)data[1]) << 0);
    return ((int32_t) val) - 0x10000u;
}

int16_t le16_to_cpu_signed(const uint8_t data[static 2]) {
    uint32_t val = (((uint32_t)data[0]) << 0) | 
                   (((uint32_t)data[1]) << 8);
    return ((int32_t) val) - 0x10000u;
}

上述哪个函数是合适的取决于数组是否包含小端或大端表示。Endianness不是这里的问题,我想知道为什么zwol从转换为int32_tuint32_t值中减去0x10000u

为什么这是正确的方法?

转换为返回类型时如何避免实现定义的行为?

既然可以假设2的补码表示,那么这个更简单的强制转换将如何失败:return(uint16_t)val

这种天真的解决方案有什么问题:

int16_t le16_to_cpu_signed(const uint8_t data[static 2]) {
    return (uint16_t)data[0] | ((uint16_t)data[1] << 8);
}

共有3个答案

汪弘盛
2023-03-14

另一种方法-使用Union

union B2I16
{
   int16_t i;
   byte    b[2];
};

节目中:

...
B2I16 conv;

conv.b[0] = first_byte;
conv.b[1] = second_byte;
int16_t result = conv.i;

第一个_字节第二个_字节可以根据小端或大端模式进行交换。这种方法不是更好,而是一种替代方法。

韦原
2023-03-14
int le16_to_cpu_signed(const uint8_t data[static 2]) {
    unsigned value = data[0] | ((unsigned)data[1] << 8);
    if (value & 0x8000)
        return -(int)(~value) - 1;
    else
        return value;
}

因为分支,它会比其他选项更贵。

这样做的目的是,它避免了任何关于平台上int表示与无符号表示之间关系的假设。转换为int需要保留适合目标类型的任何数字的算术值。因为反转确保16位数字的顶部位为零,所以该值将适合。然后一元-和1的减法应用2的补码否定的一般规则。根据平台的不同,INT16_MIN如果不适合目标上的int类型,仍可能溢出,在这种情况下,应使用long

问题中与原始版本的差异出现在返回时间。虽然原始只是总是减去0x10000和2的补码让签名溢出将其包装到int16_t范围,但此版本具有显式的if,避免了签名包装(未定义)。

现在在实践中,今天使用的几乎所有平台都使用2的补码表示。事实上,如果平台具有符合标准的stdint。定义int32_t的h必须使用2的补码。这种方法有时适用于一些根本没有整数数据类型的脚本语言——您可以修改上面显示的浮点数操作,它将给出正确的结果。

洪旻
2023-03-14

如果int是16位,那么如果return语句中表达式的值超出int16_t的范围,则您的版本依赖于实现定义的行为。

然而,第一个版本也有类似的问题;例如,如果int32_tint的typedef,并且输入字节都是0xFF,那么返回语句中的减法结果是UINT_MAX,这在转换为int16_t时会导致实现定义的行为。

恕我直言,你链接到的答案有几个主要问题。

 类似资料:
  • GCC和Clang似乎对有符号整数和无符号整数之间的加法有不同的解释,这取决于它们的大小。为什么会这样?所有编译器和平台上的转换是否一致? 举个例子: 结果: 在这两种情况下,我们得到了-1,但其中一个被解释为无符号整数和下溢。我本以为两者都会以同样的方式转化。 那么,为什么编译器会以如此不同的方式转换它们,这保证了一致性吗?我用G11.1.0和Clang12.0测试了这个。以及Arch Linu

  • 问题内容: 在Java中,是否有一种简单而优雅的方法将无符号字节值转换为有符号字节值?例如,如果我所拥有的只是int值240(二进制(24位+ 11110000)= 32bits),如何获得该int的带符号值? 问题答案: 除了,Java没有其他无符号值。考虑以下代码段: 结果将为-1,因为最低的8位已复制到byte变量中。

  • 问题内容: 给出以下代码: (第4版记入:casablanca) 您认为将char转换为int 的“ 最佳方法 ”是什么?(“ 最佳方式 ”〜= 惯用方式 ) 我们不是在转换char的实际数值,而是在转换表示形式的值。 例如。: 问题答案: 怎么样

  • 问题内容: 在Python 3中将字节转换为十六进制字符串的正确方法是什么? 我看到了一种方法,编解码器的主张,并尝试了其他最小惊讶的可能功能,但无济于事。我只想要我的字节为十六进制! 问题答案: 从Python 3.5开始,这终于不再笨拙了: 并反向: 也适用于可变类型。 参考:https : //docs.python.org/3/library/stdtypes.html#bytes.hex

  • 问题内容: 在Python中,有什么干净而优雅的方法可以将字符串“ 1,374”或“ 21,000,000”转换为int值(如1374或21000000)? 问题答案: 这实际上取决于您从哪里获得电话号码。 如果您尝试转换的数字来自用户输入,请使用。这样,将以与用户设置以及期望值一致的方式来解析数字。 另一方面,如果您从文件中读取文件,则该文件始终使用相同的格式,使用方式或取决于您的情况。这不仅易

  • 我的目标是了解两者的互补性。 有符号整数中的等于。但是,如果您使用十六进制的或十进制的按位与它,它将等于。 在我看来,这不应该发生,因为顶部字节与结果字节相同 我的预期结果是该值不应该改变,它等于< code>-121。 我的实际结果是值发生变化。 我的猜测是,是一个。因此,顶部字节的有符号位和下部字节的无符号位将导致无符号位。但是......那不可能是对的。