【问题标题】:c struct and memcpy (byte array)c struct 和 memcpy(字节数组)
【发布时间】:2018-07-19 07:04:58
【问题描述】:

我正在接收字节缓冲区数组并尝试将其复制到结构中:

我的结构是:

typedef struct mydata_block
{
    uint8_t cmd;
    uint32_t param;
    char str_buf[10];
    uint32_t crc32;
} mydata_t;

首先,发送数据的程序如下:

blockTX.cmd = 2

blockTX.str_buf = "eee789"

blockTX.param = 1001

blockTX.crc32 = 3494074521

-

02-00-00-00-E9-03-00-00-65-65-65-37-38-39-00-00-00-00-00-00-99-58-43-D0

当收到数据时,我会使用下面的 memcpy 代码将数据复制到结构中:

    memcpy((uint8_t *)&blockRX,(uint8_t *)usbd_cdc_buffer,sizeof(blockRX));

一切看起来都很好,但不是 cmd(它的 1 个字节但有填充?在结构中?)我该如何解决这个问题?

【问题讨论】:

  • 不要使用 memcpy。您需要解析字节流,单独“理解”该值并将它们显式且单独地写入结构的成员。对填充、大小、字节顺序等的任何假设都会使您的程序不可移植,并且将来容易失败。
  • 可能有填充它是编译器特定的。我担心类型的混合,例如blockTX.str_buf = "eee789"; 不是复制字符串的方式,您应该使用strcpy
  • @cdarke 好吧,抱歉,blockTX 代码不是 c# 中的 c 代码。它实际上是:blockTX.str_buf = Encoding.ASCII.GetBytes("eee789");但我把它条带化只是为了显示数据而不是代码。
  • 更长,更慢是的。但长慢正确优于短快错误或短快不可重用。同样需要更改代码以了解新的消息结构。
  • @AndrewHenle 好点。让我们在“即使再慢一点”上妥协。 ;-)

标签: c structure microcontroller memcpy


【解决方案1】:

传输数据需要考虑填充、大小、字节序等,因此您需要正确生成和解析字节流。您可以使用类似 google protobuf 之类的东西来序列化和反序列化您的数据,使其可移植且舒适。

但如果你必须的话,你可以给结构打包属性。这消除了所有的填充和对齐限制。这让您memcpy() 结构没有填充,但代价是访问结构本身的成员速度较慢。这样做只有两个很好的理由:

  1. 结构的对齐和填充由您无法控制的力量决定(必须匹配硬件或第 3 方软件)。
  2. 作为将数据转换为主机格式的中间步骤。

【讨论】:

  • 另外,打包结构可能会导致代码无法运行。它被大量使用,因为 x86 允许它。其他硬件不允许不受限制地访问未对齐的数据。
  • 如果打包创建的代码无法运行,那么您的编译器就会损坏。 packed 属性告诉编译器该结构没有使用填充或对齐。这也意味着对结构的任何成员的访问必须处理未对齐的访问。例如,在 ARM 上读取 struct { int x; } __attribute((packed)) 会导致 4 个单独的字节读取、移位和或运算。因此速度要慢得多。
  • So GCC is broken? #pragma pack 在许多非 x86 平台上玩火。
  • 请注意,您仍然存在字节顺序问题。
  • @AndrewHenle 没有关于结构访问被破坏的内容。在获取打包结构成员的地址时,您也必须始终创建一个指向打包结构的指针,例如typedef struct { int32_t unaligned_int32; } __attribute((packed)) unaliged_uint32p;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多