菜单
首页/博客/编译器关键字

编译器关键字

各种编译器会自己定义一些关键字,他们不是标准语法(c99、c++11)中的,而是编译器自己的一些编译和优化操作。

字节对齐

在嵌入式开发中,内存对齐(Alignment)与打包(Packing)是决定数据结构在内存中如何排列的关键。理解 pragma pack 和 attribute((packed)) 的区别,以及 C99/C++11 对其的支持,是编写底层驱动(如 CAN 协议解析)的基础。

虽然它们的目的相同(取消对齐,使结构体大小紧凑),但它们的生效范围和行为有显著区别。

特性 #pragma pack(n) attribute((packed))
生效范围 对其后所有声明的结构体生效,直到遇到 pack() 或文件结束。 仅对标记该属性的特定结构体或成员生效。
标准兼容性 主要是编译器扩展(MSVC, GCC, Clang 等均支持)。 GCC 和 Clang 特有扩展,MSVC 不支持此写法。
行为逻辑 设置最大对齐边界为 n 字节。 强制取消所有成员的填充(Padding)。

举例:

#pragma pack(1)
struct Foo{
    uint8_t a;
    uint16_t b;
    uint32_t c;
};
#pragma pack()
  1. 加 pack,一个 Foo 占 7 byte;如果不加,按照4字节对齐,就会占 12 byte
  2. 用完之后记得用 #pragma pack() 来还原默认对齐,否则所有引用了这个头文件的地方,都会变成 pack(1)。对于不是一字节对齐的,这样做可能导致内存的读写速度很慢

防止头文件重复编译

#pragma once

效果和 ifdef 效果一样

#ifdef XXX_H
#define XXX_H
/* 头文件内容 */
#endif

不过这个once似乎在很古代的编译器上不能用,现在的编译器应该是都支持了

编译指定分区

__attribute__( ( section (".AXI_SRAM") ) )

attribute 是 GNU C 编译器提供的关键字,用来给变量、函数添加一些特别的属性。

section 属性,用于将数据或函数,放到可执行文件的指定段中。

使用 section 前,需要在链接器脚本中定义相应的段。

链接器脚本控制了编译后的程序的内存布局,包括各个段的位置和大小.

以下是一个简单的链接器脚本示例,它定义了一个名为 .init 的段:

SECTIONS {
   .init : {
       *(.init)
   }
}