__weak关键字和__attribute__
__weak关键字
__weak是一个c/c++编译器关键字,用于定义一个弱化符号。弱化符号是一种在链接阶段可以被覆盖的符号,允许多个同名符号存在于不同的目标文件中,而不会产生冲突。
当一个符号被声明为__weak时,它具有两个特性:
1、如果该符号在某个目标文件中被定义,那么这个定义将成为默认实现,并且可以在链接器阶段被覆盖
2、如果该符号在某个目标文件中未被定义,则该符号的默认实现将为NULL
__weak和__attribute__((weak))都是定义弱化符号的关键字或属性,作用一致
在GCC编译器中,__weak是一个预定义的关键字,用于标记弱化符号。而__attribuate__((weak))是一种编译器特性,可以通过编译器属性来指示一个符号为弱化符号
简单示例代码:
// weak.c #include <stdio.h> // 定义一个弱化的全局变量 int __attribute__((weak)) weak_variable = 10; // 定义一个弱化的函数 void __attribute__((weak)) weak_function() { printf("Default implementation of weak_function\n"); } int main() { // 使用弱化的全局变量 printf("Weak variable: %d\n", weak_variable); // 调用弱化的函数 weak_function(); return 0; } // weak2.c #include <stdio.h> int weak_variable = 20; void weak_function() { printf("weak2 implementation of weak_function\n"); } gcc -o weak weak.c weak2.c ./weak 执行结果如下: Weak variable: 20 weak2 implementation of weak_function
__attribute__
__attribute__可以用来指示执行特定的操作或者进行优化,一些常见的用法如下:
1、attribute((aligned(n))):指示编译器将变量或者类型对齐到n字节
#include <stdio.h> struct align_struct { int a; char b; } __attribute__((aligned(8))); int main() { printf("Size of struct align_struct: %zu bytes\n", sizeof(struct align_struct)); return 0; } 运行结果: Size of struct align_struct: 8 bytes
2、attribute((packed)):指示编译器不要增加结构体成员之间的任何填充字节,以节省空间
#include <stdio.h> struct my_struct { int a; char b; } __attribute__((packed)); int main() { printf("Size of struct my_struct: %zu bytes\n", sizeof(struct my_struct)); return 0; } 运行结果: Size of struct my_struct: 5 bytes
3、attribute((section("name"))):可以将函数或变量放置到指定的段(section)中
如:
#define IRQ_DEFINE(__IrqId, __IrqHandle, __arg, __IrqName, __IrqFlags) \ __attribute__((section(".section_irq_table"))) struct irq_handler_struct \ _section_item_##__IrqId##_tlb = { \ .irqid = __IrqId, \ .handler = __IrqHandle, \ .arg = __arg, \ .irqname = __IrqName, \ .irqflags = __IrqFlags, \ }
在链接脚本中:
. = ALIGN(8); .irq_table : { __section_irq_table_start = .; KEEP(*(SORT(.section_irq_table*))); __section_irq_table_end = .; }
此链接脚本的作用是将名为“.section_irq_table”的输入段中的内容与符号进行关联,并将它们放置到一个名为 ".irq_table" 的输出段中,并且确保其中的内容按地址顺序排列。同时,也定义了符号 __section_irq_table_start和 __section_irq_table_end,用于获取 ".section_irq_table" 段的起始和结束位置。
4、attribute((unused)):告诉编译器一个变量或者函数未被使用,避免编译器发出未使用变量或函数的警告