编译器关键字
各种编译器会自己定义一些关键字,他们不是标准语法(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()
- 加
pack,一个 Foo 占 7 byte;如果不加,按照4字节对齐,就会占 12 byte - 用完之后记得用
#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) } }