【问题标题】:Default union and structure alignment in C?C中的默认联合和结构对齐?
【发布时间】:2021-02-07 23:25:55
【问题描述】:

联合或结构的全局变量的默认对齐方式是什么。它们是否保证字对齐?特别是在使用 GCC 和 SDCC 时。

在代码中,函数f()是安全的,还是会导致未对齐的访问? 16 位和 32 位平台有区别吗?

#define ADDR_SIZE 8

typedef union {
   unsigned char u8[ADDR_SIZE];
} addr_t;

addr_t global_address;

void f(void) {
   uint32_t x = *((uint32_t *)&global_address) + *((uint32_t *)&global_address + 1);
}

【问题讨论】:

  • 使用编译指示来确保结构包。见HERE
  • “Word”这个词没有定义大小/宽度,所以在这里没有用。该标准不(不能)强加任何对齐。
  • Pragma 不是一个选项,因为根据项目规则,代码必须“独立于编译器”。
  • @kfx:所以你不能依赖任何对齐或结构填充等。听起来像一个 XY 问题。请说明您想要达到的目标。请注意,强制转换会调用未定义的行为和严格的别名违规。一般规则是不要投射,除非你真的需要它们并且你确切地知道它们的作用,包括所有含义!
  • @kfx,我认为 cmets 中没有任何不相关的内容。

标签: c memory-alignment


【解决方案1】:

联合或结构的全局变量的默认对齐方式是什么。

这取决于工会成员。

它们是否保证字对齐?

没有。 (假设字为 4 字节)。对齐要求很复杂。尽管它们很少大于 sizeof(int),但它们可能因每种类型而异。


在 C11 中,通过包含 max_align_t 对象,联合将根据需要与任何类型对齐。

max_align_t 这是一种对象类型,其对齐方式与所有上下文中的实现所支持的一样好; C11 §7.19 2

#include <stddef.h>

typedef union {
   max_align_t dummy;
   unsigned char u8[ADDR_SIZE];
} addr_t;

@Jens Gustedt 有关于别名的优点。只需从工会内部访问uint32_t。注意字节序问题。

typedef union {
   unsigned char u8[ADDR_SIZE];
   uint32_t u32[ADDR_SIZE/sizeof(uint32_t)];
} addr_t;

【讨论】:

    【解决方案2】:

    除非您使用例如__attribute__((aligned(4))) 指定对齐要求,否则您不能保证联合正确对齐。

    使用char 仔细安排全局变量,如下所示:

    ...
    #define ADDR_SIZE 8
    
    typedef union {
       unsigned char u8[ADDR_SIZE];
    } addr_t;
    
    addr_t global_address1;
    char padd1;
    addr_t global_address2;
    addr_t global_address3;
    ...
    

    你可以在这里see奇数地址:

    0x804971d * &global_address1
    0x8049714
    0x8049715 * &global_address2
    0x804970c
    

    在某些具有严格对齐要求的架构中尝试访问这些地址将导致一些未对齐的访问异常并停止程序。其他可以以性能为代价处理未对齐访问的架构将需要至少两个内存读取周期,而需要多个 CPU 周期才能完成。

    【讨论】:

    • "除非您指定对齐要求......您不能保证并集正确对齐。" --.还有其他保证方式。
    • 不保证提供的代码会导致global_address2 小于字对齐。
    猜你喜欢
    • 2021-05-28
    • 2012-12-11
    • 1970-01-01
    • 1970-01-01
    • 2015-06-08
    • 1970-01-01
    • 2010-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多