c - 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
解决方案
如果您的 C 实现提供了一种方法来确保结构的布局与相关驱动程序用于写入缓冲区的布局相同,那么解决此问题的一个很好的方法是让驱动程序直接写入结构。我在这里推断驱动程序函数的签名,但这可能类似于:
UART2_readTimeout(uartR2, (uint8_t *) &values, 54, NULL, 500);
假设它是oruint8_t
的别名,通过类型指针写入结构的表示是有效的。因此,这避免了您必须制作副本。unsigned char
char
uint8_t *
然而,诀窍在于结构布局。假设您希望数据按照给定的顺序排列为给定的结构成员,没有间隙,这样的结构布局将阻止结构实例定位在内存中,以便所有成员在其倍数的地址上对齐尺寸。根据硬件的对齐规则,这可能非常好,但可能会减慢对某些成员的访问速度,或者尝试访问某些成员会使程序崩溃。
如果您仍想继续,则需要查看编译器的文档以获取有关如何获得所需结构布局的信息。您可能会查找对结构“打包”、结构布局或结构成员对齐的引用。没有标准的方法来做到这一点——如果你的 C 实现完全支持它,那么它就构成了一个扩展,具有特定于实现的细节。
所有相同的问题和注意事项都适用于memcpy
将缓冲区内容复制到结构类型的实例上,因此,如果您没有数据的多个副本并且您可以安排将批量复制到结构上工作,那么您最好直接写入结构而不是写入单独的缓冲区然后复制。
另一方面,安全和标准的替代方案是允许您的实现以它认为最好的方式布置结构,并以逐个成员的方式将数据从缓冲区复制到结构中,每个成员memcpy()
s. 是的,代码会有点乏味,但它不会对对齐相关的问题敏感,甚至对重新排序结构成员或添加新成员也不敏感。
推荐阅读
- python - 如何正确设置库根目录?
- c# - .NET 中的低级弹性搜索使用
- java - CSV 以外格式的多部分无法在类路径上找到文件
- r - 根据列中的分类值从具有不同抽取的 data.table 中随机抽样
- vue.js - 有没有办法通过在 Vue 实例中硬编码来“发出”内置事件?
- html - SVG 边界框 - 超链接
- php - PhpSpreadsheet 单元格验证规则以禁止无效输入
- python - Tkinter Fibonacci 程序仅显示第一个数字(python 3)Ki
- python - 为什么 conda 在激活另一个环境后重新定义基础环境?
- reactjs - 在函数内需要具有动态路径的文件时如何修复 eslint 失败?