c - GCC 变量对齐问题

标签 c gcc memory-alignment compiler-flags microblaze

我正在为 Microblaze 处理器使用 GCC 编译器。
最近遇到了变量对齐的问题。我注意到有时编译器将静态变量分配给未对齐的地址(地址不能被 4 整除),因此如果我将未对齐变量的指针发送到任何函数,我会得到未对齐访问硬件异常。

我有两个关于该主题的问题:

  • 如何确保所有静态变量都对齐?有没有强制这样做的标志?目前我正在使用变量属性:
    __attribute__((aligned(4)))
    

    但这很不舒服,因为我需要为我拥有的每个静态变量定义它,这是没有意义的。
  • 有没有办法确保我的函数局部变量(在堆栈中分配)将对齐?我的意思是有没有办法确保我的堆栈头对齐,每个函数都使用堆栈的对齐部分,并且堆栈中分配的任何变量都是对齐的。

  • 谢谢。

    最佳答案

    AFAIK 没有办法告诉 GCC 你想对整个编译单元强制执行某种对齐。那就是没有像“alignment_unit 4”这样的编译器标志。

    我不是这个主题的专家(尤其不是 Microblaze 软核),但我对 GCC 进行了一些实验,针对我 PC 的 Intel x64 CPU 和针对 ARM Cortex-M4 微 Controller 的 IAR C。

    SETUP 1:全局(文件级)变量

    static uint64_t a = 0;
    static uint8_t b = 0;
    static uint16_t c = 0;
    static uint16_t d = 0;
    static uint8_t e = 0;
    
    int main()
    {   
        printf("&a = %u\n", &a);
        printf("&b = %u\n", &b);
        printf("&c = %u\n", &c);
        printf("&d = %u\n", &d);
        printf("&e = %u\n", &e);
    
        return 0;
    }
    

    SETUP 2 : 本地(函数级)变量
    void some_func()
    {    
        uint64_t a = 0;
        uint8_t b = 0;
        uint16_t c = 0;
        uint16_t d = 0;
        uint8_t e = 0;
    
        printf("&a = %u\n", &a);
        printf("&b = %u\n", &b);
        printf("&c = %u\n", &c);
        printf("&d = %u\n", &d);
        printf("&e = %u\n", &e);
    }
    
    int main()
    {   
        some_func();    
        return 0;
    }
    

    我关闭了所有优化。

    两种设置都不会导致 4 字节(或 PC 为 8 字节)对齐的变量地址。编译器/平台组合都是这种情况。

    我能想到的唯一可能的解决方案(尽管可能不优雅)是为自定义类型创建一个 header 并将以下 typedef 放在那里:
    typedef __attribute__((aligned(4))) uint64_t ui64_aligned;
    typedef __attribute__((aligned(4))) uint32_t ui32_aligned;
    typedef __attribute__((aligned(4))) uint16_t ui16_aligned;
    typedef __attribute__((aligned(4))) uint8_t ui8_aligned;
    

    然后只需在需要时使用“对齐类型”。这样,您将同时拥有“自定义对齐”和“自动对齐”类型,并且您也不会损害代码可读性(太多......)。

    我知道这不是您正在寻找的解决方案,但这至少有效(就我的测试而言)。

    关于c - GCC 变量对齐问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40862244/

    相关文章:

    c++ - 这些对齐功能之间有什么区别?

    ios - 从 NSDataAsset 读取时偶尔崩溃

    C++ 类打包/成员对齐

    c - 字符串修剪导致内存泄漏?

    c - Eclipse C/C++ 在构建时不包含文件

    c++ - gcc 4.6 编译器的奇怪行为

    linux - Linux ld-linux.so 的版本化符号

    c - ctype.h 中部分函数的优化实现

    c - C 中奇怪的输出缓冲行为

    c++ - gcc 版本 4 和 5 和 6 之间的区别