首页 > 解决方案 > C 中的 Memcpy - 在 for 循环中使用数组然后分配给结构

问题描述

我正在使用for循环将数组从 UART RX 缓冲区复制到内存。

如下所示:

UART2_readTimeout(uartR2, rxBuf3, 54, NULL, 500);
GPIO_toggle(CONFIG_GPIO_LED_3);

if ((rxBuf3[4] == 0x8C) && (rxBuf3[10] != 0x8C)) {
    int i;
    for (i = 0; i < 47; i++) {
        sioR2[i]=rxBuf3[i];
    }

然后,我想使用struct如下所示的方法,以便在处理和组织数据时使用点表示法:

typedef struct
{
  uint16_t voltage;
  uint16_t current;
  uint16_t outTemp;
  uint16_t inTemp;
  uint16_t status;
  uint32_t FaultA;
  uint32_t FaultB;
  uint32_t FaultC;
  uint32_t FaultD;
  uint8_t softwareMode;
  uint8_t logicLoad;
  uint8_t outputBits;
  uint16_t powerOut;
  uint32_t runHours;
  uint16_t unitAddresses[6];
} unitValues;

假设它们的总长度相同,是否可以memcpy对整个数组执行 a 到结构的单个实例?

Array  : 001110101....110001
         |||||||||||||||||||   <- memcpy
         vvvvvvvvvvvvvvvvvvv
Struct : 001110101....110001

标签: cmemoryembeddedmemcpy

解决方案


如果您的 C 实现提供了一种方法来确保结构的布局与相关驱动程序用于写入缓冲区的布局相同,那么解决此问题的一个很好的方法是让驱动程序直接写入结构。我在这里推断驱动程序函数的签名,但这可能类似于:

UART2_readTimeout(uartR2, (uint8_t *) &values, 54, NULL, 500);

假设它是oruint8_t的别名,通过类型指针写入结构的表示是有效的。因此,这避免了您必须制作副本。unsigned charcharuint8_t *

然而,诀窍在于结构布局。假设您希望数据按照给定的顺序排列为给定的结构成员,没有间隙,这样的结构布局将阻止结构实例定位在内存中,以便所有成员在其倍数的地址上对齐尺寸。根据硬件的对齐规则,这可能非常好,但可能会减慢对某些成员的访问速度,或者尝试访问某些成员会使程序崩溃。

如果您仍想继续,则需要查看编译器的文档以获取有关如何获得所需结构布局的信息。您可能会查找对结构“打包”、结构布局或结构成员对齐的引用。没有标准的方法来做到这一点——如果你的 C 实现完全支持它,那么它就构成了一个扩展,具有特定于实现的细节。

所有相同的问题和注意事项都适用于memcpy将缓冲区内容复制到结构类型的实例上,因此,如果您没有数据的多个副本并且您可以安排将批量复制到结构上工作,那么您最好直接写入结构而不是写入单独的缓冲区然后复制。


另一方面,安全和标准的替代方案是允许您的实现以它认为最好的方式布置结构,并以逐个成员的方式将数据从缓冲区复制到结构中,每个成员memcpy()s. 是的,代码会有点乏味,但它不会对对齐相关的问题敏感,甚至对重新排序结构成员或添加新成员也不敏感。


推荐阅读