【问题标题】:Combine 2 bytes into a short int in C在C中将2个字节组合成一个短整数
【发布时间】:2017-09-12 00:28:30
【问题描述】:

我通过网络数据包接收一个短整数,这意味着它将以网络字节顺序(大端)的 2 个字节出现。

我想在我的机器上将收到的两个字节组合成一个短 int 变量,它是 little endian 字节顺序。

例子:

short int test = 400; //0x190 in big endian, 0x9001 in little endian
char testResponse[2] = {0x01, 0x90};
//here is my attempt
short int result = testResponse[1] << 8 | testResponse[0];
printf("%d\n", result); //-28671 when expecting 400

任何帮助将不胜感激!

【问题讨论】:

  • 你有什么问题?
  • 组合这两个数字的方法似乎是比 OR 左移 8 位,但这似乎没有给出正确的结果,所以我想知道是否有人知道我的位算术是错误的。
  • C 中没有“8 位左移”。如果有,8 的移位计数将调用未定义的行为。您最有可能受到整数促销,了解它们!并使用固定宽度的无符号类型。 char 不保证是无符号的,也不保证有 8 位。根据您对现已删除的答案的评论:我们需要所有相关信息。或者你得到正确的代码,就像我说的那样。
  • 字节序是字节在内存中的存储方式,而不是计算值的方式。要获得0x0190,您需要0x01 &lt;&lt; 8 + 0x90
  • @JeremyRobertson 你得到short int result = testResponse[0] &lt;&lt; 8 | testResponse[1]; printf("%d\n", result); 的预期答案了吗(交换了索引)?

标签: c network-programming int hex bit-shift


【解决方案1】:
#include <arpa/inet.h>
#include <string.h>

int16_t result;
memcpy(&result, testResponse, sizeof(int16_t));
result = (int16_t)ntohs((uint16_t)result);

某些平台(例如 32 位 arm)不允许未对齐的访问。因此,在调用 ntoh 之前,请使用 memcpy 将其转换为正确大小的 int。

【讨论】:

  • 迂腐:*(uint16_t *)testResponse 是 UB,因为 char testResponse[] 可能不符合 uint16_t 的对齐要求。
  • 它甚至不是迂腐,但在许多 ARM 处理器上都很实用。此外,即使在未对齐访问可能起作用的平台上,严格别名编译器也可能出现异常。
  • @chux 是正确的。我添加了一个 memcpy 来解决对齐问题。
【解决方案2】:

您混淆了索引。小端的数字是 0x0190,但你的代码计算的是大端的数字,即0x9001,简而言之,它也会在左移到符号位时导致整数溢出。

代码确实不是很便携,因为char 可能已签名或未签名。虽然大多数架构都有无符号字符可能是真的,但事实是大多数 C 程序都是为有符号字符架构(x86)编写的。 0x90 被符号扩展的事实可能会导致意想不到的结果。

因此更便携

char testResponse[2] = {0x01, 0x90};
unsigned int tmp = (unsigned)testResponse[0] << 8 | (unsigned)testResponse[1];
short result = tmp;  // implementation-defined behaviour
printf("%d\n", result); // 400

【讨论】:

    猜你喜欢
    • 2013-04-19
    • 2022-06-17
    • 2013-08-17
    • 2021-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多