【问题标题】:converting/combining two uint8_t to int16_t in Objective-C在 Objective-C 中将两个 uint8_t 转换/组合为 int16_t
【发布时间】:2013-12-01 07:43:32
【问题描述】:

假设我有一个用 uint8_t 填充的缓冲区,就像我通过执行得到的一样

uint8_t buffer[4];    
[inputStream read:buffer maxLength:4];

再次,假设我知道这个缓冲区现在包含两个大端格式的有符号 16 位整数(即使缓冲区的类型是 uint8_t)。 我将如何获得每个数字的结果?

我认为您必须使用按位运算符,并且您还必须从无符号转换为有符号,但我似乎无法完全弄清楚。

只有 uint8_t 值的类似示例如下所示:

uint8_t buffer[2];
[inputStream read:buffer maxLength:2];
uint8_t value1 = buffer[0];
uint8_t value2 = buffer[1];

任何帮助将不胜感激,因为我确信这是一个相对简单的问题。

更新: 为了进一步澄清问题: 我提前知道我收到了 0 到 255 的数字,即使它们是 16 位签名的。所以收到的任何负数都是不正确的,应该向上移动 127,以说明有符号/无符号的差异。

【问题讨论】:

    标签: ios objective-c c


    【解决方案1】:

    要从大端转换为小端,可以使用有符号短格式

    (来自:convert big endian to little endian in C [without using provided func]

    int16_t swap_int16( int16_t val ) 
    {
        return (val << 8) | ((val >> 8) & 0xFF);
    }
    

    所以回到你的代码

    uint8_t buffer[4];    
    [inputStream read:buffer maxLength:4];
    

    你可以试试:

    int16_t *value1;
    int16_t *value2;
    
    // set the pointers to the correct buffer location
    
    value1 = (int16_t *)(&buffer[0]);
    value2 = (int16_t *)(&buffer[2]);
    
    // perform the conversion
    
    *value1 = swap_int16( *value1 );
    *value2 = swap_int16( *value2 );
    
    // finally you may want to check the result
    
    printf("Value1: %d\n", *value1 );
    printf("Value2: %d\n", *value2 );
    

    请注意,这种方法将交换 buffer

    中的原始字节

    【讨论】:

    • 您的答案最终给出了与预期答案 127 之间的距离。因此,例如,如果 value1 的预期值为 134,您的答案将返回 7。如果预期值为 118,您的答案将返回 -9。我假设这是因为没有进行符号调整。显然,我可以将 127 添加到每个结构,但我想了解发生了什么。除此之外,很好的答案,感谢您的快速回复!
    • 尽我所能提供帮助。我会检查我是否犯了任何错误。我同意远离“添加 127 来修复但不知道为什么”。
    • 这不仅是错误的,而且还会不必要地混淆指针别名,从而导致 UB。这里正确的做法是使用无符号算术和位运算符,例如uint16_t word = (byte1 &lt;&lt; 8) | byte0
    • @Ethan Gill:我更新了我的答案。以前的版本实际上没有正确处理该标志。我还试图使代码更简洁明了。我有兴趣收到反馈。希望它现在有效。
    • @Paolo 我正式是个白痴。我一直通过我的流错误地发送数据。您的新解决方案完美运行!非常感谢您的帮助。
    【解决方案2】:

    最安全的方法是使用下面的

    #import <arpa/inet.h>
    #import <stdint.h>
    #import <string.h>
    
    
    uint8_t* p = buffer;
    uint16_t x0;
    memcpy(&x0, p, sizeof(x0));
    x0 =ntohs(x0);
    
    uint16_t x1;
    p += sizeof(uint16_t);
    memcpy(&x1, p, sizeof(x1));
    x1 = ntohs(x1);
    

    即使缓冲区的字节与 uint16_t 值未对齐(因此,使用memcpy),这也有效。

    由于网络字节顺序恰好等于“大端”,您可以使用ntohs,其内容为“将网络字节顺序短交换为主机字节顺序”。

    另见:

    $man ntohs
    

    【讨论】:

    • 还有一些更清晰的CF方法用于字节交换,例如CFSwapInt16BigToHost(bigEndian16)
    猜你喜欢
    • 2021-12-04
    • 2018-09-07
    • 2022-11-10
    • 2012-04-29
    • 2017-06-13
    • 2020-05-28
    • 2020-07-08
    • 1970-01-01
    相关资源
    最近更新 更多