gpt4 book ai didi

c - 在 C 编程中将结构指针传递给函数和结构填充

转载 作者:行者123 更新时间:2023-11-30 15:05:13 26 4
gpt4 key购买 nike

build_uart_frame() 中,我调用 calcFCS() 来计算结构体成员(len、cmd0、cmd1 和 data)中所有字节的异或。

我认为该结构没有被填充,因此调用 calcFCS() 会出现问题吗?有人可以解释一下与结构填充相关的问题是什么,因为我不理解它在这里的作用,其次我怎样才能正确地执行此操作?

谢谢

typedef struct uart_frame {
uint8_t sof; /* 1 byte */
uint8_t len; /* 1 bytes */
uint8_t cmd0; /* 1 byte */
uint8_t cmd1;
char data[11]; /* 0 -250 byte */
unsigned char fcs; /* 1 byte */
} uart_frame_t;

//-------------------------------------------------------------------------

// Global uart frame
uart_frame_t rdata;

//-------------------------------------------------------------------------
unsigned char calcFCS(unsigned char *pMsg, unsigned char len) {

unsigned char result = 0;
while(len--) {
result ^= *pMsg++;
}

return(result);
}

//-------------------------------------------------------------------------

// Worker code to populate the frame

int build_uart_frame() {

uart_frame_t *rd = &rdata; //pointer variable 'rd' of type uart_frame

// common header codes
rd->sof = 0xFE;
rd->len = 11;
rd->cmd0 = 0x22;
rd->cmd0 = 0x05;
snprintf(rd->data, sizeof(rd->data), "%s", "Hello World");
rd->fcs = calcFCS((unsigned char *)rd, sizeof(uart_frame_t) - 1); //issue with struct padding
return 0;
}

最佳答案

鉴于您非常具体的示例,填充不太可能成为问题,因为所有数据类型都是字节。当您使用较大的数据类型时,填充通常是一个问题,因为这些数据类型通常不应分配在未对齐的地址处。

但这并不能保证:理论上,如果编译器认为这样会获得更快的代码,它可以决定用 int 替换 char。可以在结构中的任何位置自由插入任意数量的填充,除了最顶部。

这就是为什么结构不适合描述内存映射或数据协议(protocol)。您必须确保不存在填充物,并且最好是可移植的。确保这是标准 C 编译时断言的最佳方法:

_Static_assert(sizeof(uart_frame_t) == offsetof(uart_frame_t, fcs)+sizeof(unsigned char), 
"Padding detected");

这里根据最后一个结构成员的字节位置+该成员的大小检查整个结构的大小。如果它们相同,则没有填充。

当然,这只能防止您的代码编译和行为不当,并不能解决实际问题。不幸的是,没有可移植的方法来阻止填充。 #pragma pack(1) 很常见,但非标准。 __attribute__((packed)) 是另一个特定于编译器的命令。

确保编译代码的给定系统上不存在打包通常就足够了。

此外,一些更奇特的系统(MIPS、SPARC 等)甚至不支持未对齐读取,这意味着未对齐访问不仅意味着代码速度较慢,还意味着运行时总线错误崩溃。

<小时/>

使用结构安全地确保代码最大可移植性的唯一方法是编写序列化/反序列化例程,手动将每个成员复制到原始字节数组或从原始字节数组复制每个成员:

void uart_serialize (const uart_frame_t* frame, uint8_t* raw)
{
raw[0] = frame->sof;
raw[1] = frame->len;
...
memcpy(&raw[4], frame->data, 11);
...
}

此类方法的缺点是它们显然会增加一些执行时间,因此我只会将它们用于我知道需要移植到各种不同系统的代码。

关于c - 在 C 编程中将结构指针传递给函数和结构填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39955797/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com