结构是否只包含无填充字符?

如何解决结构是否只包含无填充字符?

我有一些遗留代码(目标架构 armv5tejl 和 armv7l)声明了如下所示的结构:

#pragma pack(push,1)
struct modbus_pkt_s
{
    uint8_t d_addr;
    uint8_t cmd;
    uint8_t payload[250];
    uint8_t payload_length;
    uint8_t pkt_length;
    modbus_erc_t erc;
};
#pragma pack(pop) 

其中 modbus_erc_t 是枚举:

typedef enum modbus_erc_e modbus_erc_t;

我还有一个函数来计算 modbus 数据包的 CRC(它使用 d_addrcmdpayload),它假设前三个结构体字段被打包。

我想删除 #pragma 指令,因为我遇到了未对齐的内存访问问题(导致 SIGBUS)。

考虑到它们是无符号字符,我可以安全地删除那些 #pragma 指令并假设前三个字段要打包吗?

解决方法

C 标准没有在结构中指定填充;允许编译器出于任何原因在成员之间插入填充。编译器通常没有理由在大小为一字节的成员或这样的数组之前插入填充,而 GCC 和 Clang 则没有。 (可以想象,在某些体系结构中对齐数组可能会有一点好处,使基地址更简单。这在这里不是实际问题。)

即使较早的成员不是单字节类型,您也可以通过删除围绕结构的 #pragma 指令并用 __attribute__((__packed__)) 标记每个较早的元素来获得您请求的布局。例如,这段代码:

#include <stdio.h>


int main(void)
{
    typedef struct
    {
        char a __attribute__((__packed__));
        int  b __attribute__((__packed__));
        int  c;
    } foo;
    foo x = {0x1,0x02030405,0x06070809};
    unsigned char *p = (void *) &x;
    for (size_t i = 0; i < sizeof x; ++i)
        printf("%02hhx ",p[i]);
    printf("\n");
}

Apple Clang 11 显示第一个 int 已打包,但第二个正常对齐:

01 05 04 03 02 00 00 00 09 08 07 06

然而,虽然删除 pragma 指令仍会使您的早期成员打包在 GCC 和 Clang 中,但它可能会移动 erc 成员。该结构被打包是有原因的,很可能原因不仅仅是 CRC 可以假设早期成员被打包。这种打包通常是针对通过某个通信通道传输的结构完成的,仅更改通道一侧的结构会中断通信——发送方和接收方将使用不同的布局。

此外,您遇到未对齐的访问错误这一事实表明您的程序除了使用压缩结构之外还做错了什么。当一个结构被打包时,编译器会生成正确的代码来访问它的未对齐成员。要获得错误,程序必须执行其他操作,例如将打包的 modbus_erc_t 成员的地址分配给未标记为打包的 modbus_erc_t *,然后尝试取消引用该指针。如果是这样,该代码已损坏,应该修复。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?