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

标签 c casting language-lawyer

this answer中,zwol提出了以下要求:

The correct way to convert two bytes of data from an external source into a 16-bit signed integer is with helper functions like this:



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

上面的哪个函数合适,取决于数组是包含小端还是大端表示。字节序不是这里要讨论的问题,我想知道为什么zwol从转换为0x10000uuint32_t值中减去int32_t

为什么这是正确的方法?

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

既然可以假设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);
}

最佳答案

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

但是第一个版本也有类似的问题。例如,如果int32_tint的typedef,并且输入字节均为0xFF,则return语句中的减法结果为UINT_MAX,当转换为int16_t时,会导致实现定义的行为。

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

关于c - 将2个字节转换为带符号的16位整数的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60864450/

相关文章:

ios - 我在哪里可以找到 libsystem_c.dylib 的源代码?

c - 使用 snprintf 在开头追加

c - 可以复制 CRITICAL_SECTION 吗?

c - 这个指针转换是否违反了严格的别名规则?

c++ - 将尾调用 void (i32, ...) bitcast 转换为 llvm::Function 以获取 FnAttribute

c++ - static_casting a constexpr void* 的结果是常量表达式吗?

c - fgetc() 的 C 段错误原因

Python:如何更新嵌套字典中键值对的值?

c - 在字符串文字中使用哪些字符是合法的?

c++ - "temporary of type ' A ' has protected destructor", 但它的类型是 B