【问题标题】:C: Converting unsigned char array to signed int (vice versa)C:将无符号字符数组转换为有符号整数(反之亦然)
【发布时间】:2016-02-27 09:44:39
【问题描述】:

我正在尝试将无符号字符数组缓冲区转换为有符号整数(反之亦然)。

下面是演示代码:

int main(int argv, char* argc[])
{
    int original = 1054;
    unsigned int i = 1054;
    unsigned char c[4];
    int num;

    memcpy(c, (char*)&i, sizeof(int));

    //num  = *(int*) c;                          // method 1 get
    memcpy((char *)&num, c, sizeof(int));        // method 2 get
    printf("%d\n", num);

    return 0;
}

1) 我应该使用哪种方法从 unsigned char[] 获取到 int?

方法 1 获取还是方法 2 获取? (或任何建议)

2) 如何将 int 原始转换为 unsigned char[]?

我需要通过一个只接受 unsigned char[] 的缓冲区发送这个整数

目前我正在做的是将 int 转换为 unsigned int 然后转换为 char[],例如:

int g = 1054;
unsigned char buf[4];
unsigned int n;
n = g;
memcpy(buf, (char*)&n, sizeof(int));

虽然它工作正常,但我不确定它是否正确或安全?

PS。我正在尝试通过 USB 串行通信(在 Raspberry Pi 和 Arduino 之间)在 2 个设备之间发送数据

【问题讨论】:

  • 不确定它是否安全,但减少不安全的一件事是说unsigned char buf[sizeof(int)]而不是unsigned char buf[4]
  • 如果char数组没有正确对齐,方法1可能会导致segfault
  • num = *(int *)c 不要那样做,c 不需要正确对齐 int
  • 好的,感谢您的所有建议!应该坚持 memcpy 方法!
  • *(int *)c 也违反了严格的别名规则,不要这样做

标签: c arrays


【解决方案1】:

无论机器上的字节序如何,以下方法都可以工作(假设sizeof(int)==4):

unsigned char bytes[4];
unsigned int n = 45;

bytes[3] = (n >> 24) & 0xFF;
bytes[2] = (n >> 16) & 0xFF;
bytes[3] = (n >> 8) & 0xFF;
bytes[0] = n & 0xFF;

以上代码以小端方式将整数转换为字节数组。这里是link,还有更多信息。

对于反向操作,请参阅答案here

您使用memcpy 的方法可能会在不同的计算机上产生不同的结果。因为memcpy 会将源地址中的任何内容复制到目标地址,并且根据计算机是小端还是大端,起始源地址可能有 LSB 或 MSB。

【讨论】:

  • 赞成,尽管所有这些 & 0xff 实际上并不是必需的(但他们可能会添加一些清晰的东西)。
  • 使用你的代码,它给了我另一个字节序的结果(c 数组是我目前正在使用并且正在工作的数组,字节数组是你建议的数组): c[i] = 0x2d c [i] = 0x0 c[i] = 0x0 c[i] = 0x0 字节[i] = 0x0 字节[i] = 0x0 字节[i] = 0x0 字节[i] = 0x2d
  • @Somebody union 会在不同的机器上给出不同的结果,原因与 memcpy 类似
  • @Giorgi 只是好奇,为什么不管机器上的字节序如何,这种小字节序方式都可以工作?我尝试在安卓设备上通过蓝牙进行测试,树莓派和大端方式有效,而小端方式不起作用。只是对所有这些字节序感到好奇哈
  • @DoeJoe 不是小端有效,而大则不是。这就是方法。我提到的方法,如果您使用该方法以小端方式编码整数,并应用类似的反向操作(假设字节以小端方式从字节数组中恢复整数),在不同的机器上,您将得到相同的结果。即使您以大端方式转换整数,相同的方法也适用于任何机器。现在,您的设备可能需要某种字节序的整数,这是不同的事情。您可能需要对字节顺序进行更多研究。
【解决方案2】:

您可以将int(或unsigned int)和unsigned char 数组存储为union。这种方法称为type punning,自 C99 以来,它已完全按照标准进行了清理(不过,这是之前的常见做法)。假设sizeof(int) == 4

#include <stdio.h>

union device_buffer {
    int i;
    unsigned char c[4];
};

int main(int argv, char* argc[])
{
    int original = 1054;

    union device_buffer db;
    db.i = original;

    for (int i = 0; i < 4; i++) {
        printf("c[i] = 0x%x\n", db.c[i]);
    }
}

请注意,数组中的值是由于byte order 存储的,即字节序。

【讨论】:

  • 我在 stackoverflow 的某个地方看到 memcpy 和 union 可能会产生不同的结果!真的吗? union 和 struct 有什么区别?非常感谢!
  • 请注意,通过 union 的类型双关语在 C++ 中仍然是 UB;普遍安全的方式仍然是memcpy
  • @DoeJoe: char 是我的错字,现在它是正确的。对于第二个问题,只要您在同一台机器上运行代码,memcpy 和 union 的结果应该完全相同。
  • @DoeJoe:除非您存储的值超出了int 的范围,否则这无关紧要。不管怎样,我改成了unsigned,因为你的问题就是这样。
  • 如果 int 小于 4 个字符,那么这是 ub:db.i = original; 剩余的字符未初始化。
猜你喜欢
  • 2011-10-14
  • 1970-01-01
  • 2011-08-09
  • 2011-11-08
  • 1970-01-01
  • 2019-07-23
  • 2021-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多