__attribute__
是 GCC 和 Clang 编译器中的一种语言扩展,用于给函数、变量、类型等添加属性,以便调整编译行为和优化。以下是一些常见的 __attribute__
用法及其详细说明:
基本语法
__attribute__((attribute-list))
其中 attribute-list
是一个用逗号分隔的属性列表。
常见属性
以下是一些常用的 __attribute__
属性及其作用:
deprecated
: 标记函数为已废弃,调用时会发出警告。unused
: 标记变量为未使用,防止编译器发出未使用变量警告。noreturn
: 标记函数不返回,编译器会进行相应优化。aligned
: 指定变量的对齐方式。packed
: 指示编译器为结构体优化空间,而不是默认对齐。format
: 检查像printf
、scanf
这类函数的格式字符串。
使用语法规则
1. 对于函数
属性应放在函数声明的尾部,但在函数定义时,属性必须放在返回类型之前,甚至可以放在声明的中间部分。
声明:属性在函数名之后
void warning_func() __attribute__((deprecated));
定义:属性在返回类型之后
__attribute__((deprecated)) void warning_func() {
// 函数实现
}
2. 对于变量
属性可以放在变量声明或定义的末尾。
int unused_var __attribute__((unused));
3. 对于类型
属性可以放在类型定义的末尾。
typedef int int32 __attribute__((aligned(4)));
例子和详细解释
常见的 __attribute__
用法
__attribute__((aligned(alignment)))
: 指定变量、结构体或联合体的对齐方式。
int x __attribute__((aligned(16))); // x 对齐到 16 字节边界
__attribute__((packed))
: 告诉编译器不要为结构体字段添加填充字节。
struct __attribute__((packed)) PackedStruct {
char c;
int i;
};
__attribute__((deprecated))
: 标记函数或变量为不推荐使用,如果使用会产生警告。
void old_function() __attribute__((deprecated));
void old_function() {
// implementation
}
__attribute__((noreturn))
: 告诉编译器函数不会返回。
void fatal_error(const char *msg) __attribute__((noreturn));
void fatal_error(const char *msg) {
// implementation
exit(1);
}
__attribute__((format(archtype, string-index, first-to-check)))
: 检查函数的格式化字符串是否正确。例如,类似 printf
的函数。
void my_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void my_printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
#include <stdio.h>
void my_printf(__attribute__((format(printf, 1, 2))) const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
void test_func() {
my_printf("%s %d\n", "test"); // 编译时会检查格式字符串
}
__attribute__((unused))
: 防止编译器对未使用的变量、函数或参数发出警告。
void func(int unused_param __attribute__((unused))) {
// implementation
}
__attribute__((visibility("default")))
: 设置符号的可见性,用于控制符号导出。
int public_variable __attribute__((visibility("default")));
__attribute__((cleanup(cleanup_function)))
: 指定一个函数,当变量超出作用域时自动调用此函数。
void cleanup_function(void *ptr) {
free(*(void **)ptr);
}
void example() {
void *ptr __attribute__((cleanup(cleanup_function))) = malloc(100);
// 当 ptr 超出作用域时,cleanup_function 会被自动调用
}
__attribute__((section("section_name")))
: 将变量或函数放入指定的段中。
int special_variable __attribute__((section("special_section")));
__attribute__((regmap(3)))
: fastcall
是一种调用约定,它使用寄存器来传递函数参数,从而加快函数调用的速度。具体来说,regparm(3)
表示最多使用三个寄存器来传递参数,这可以减少栈操作,提高性能。
#define fastcall __attribute__((regparm(3)))
fastcall int add(int a, int b) {
return a + b;
}
示例1
以下是一个综合示例,演示了多种 __attribute__
用法:
#include <stdio.h>
#include <stdlib.h>
// 定义一个对齐到 16 字节的结构体
struct __attribute__((aligned(16))) AlignedStruct {
int a;
char b;
};
// 定义一个打包的结构体
struct __attribute__((packed)) PackedStruct {
char c;
int d;
};
// 不推荐使用的函数
void old_function() __attribute__((deprecated));
void old_function() {
printf("This is a deprecated function.\n");
}
// 不返回的函数
void fatal_error(const char *msg) __attribute__((noreturn));
void fatal_error(const char *msg) {
fprintf(stderr, "Fatal error: %s\n", msg);
exit(1);
}
// 格式化字符串检查函数
void my_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void my_printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
// 自动清理的变量
void cleanup_function(void *ptr) {
free(*(void **)ptr);
}
void example() {
void *ptr __attribute__((cleanup(cleanup_function))) = malloc(100);
// 使用 ptr...
// 当 ptr 超出作用域时,cleanup_function 会被自动调用
}
// 放入特定段的变量
int special_variable __attribute__((section("special_section")));
int main() {
struct AlignedStruct as;
struct PackedStruct ps;
old_function(); // 使用不推荐的函数,会产生警告
// 调用不会返回的函数
// fatal_error("Something went wrong!");
// 使用格式化字符串检查的函数
my_printf("Hello, %s!\n", "world");
example();
// 使用放入特定段的变量
printf("special_variable = %d\n", special_variable);
return 0;
}
示例2
static const char __kstrtab_init_mm[]
__attribute__((section("__ksymtab_strings")))
= "init_mm";
解释
-
static
: 关键字static
表示该变量的作用域仅限于当前文件,不能被其他文件访问。 -
const char
:const
表示该字符串是只读的,不可修改。char
类型表示这是一个字符数组。 -
__kstrtab_init_mm[]
: 变量名,表示这是一个字符数组。 -
__attribute__((section("__ksymtab_strings")))
: 将该变量放入名为__ksymtab_strings
的段中。这个属性告诉编译器将该变量存储在指定的段中,而不是默认的段。 -
= "init_mm"
: 变量的初始值,表示这是一个以init_mm
作为内容的字符串。
section
属性用于将变量、函数等放入指定的段中。在内核开发和系统编程中,特定的段可以用于管理特定类型的数据。例如,__ksymtab_strings
段通常用于存储内核符号表的字符串。
#include <stdio.h>
// 将字符串放入名为 __ksymtab_strings 的段中
static const char __kstrtab_init_mm[] __attribute__((section("__ksymtab_strings"))) = "init_mm";
static const char __kstrtab_start_kernel[] __attribute__((section("__ksymtab_strings"))) = "start_kernel";
// 示例函数,用于展示如何使用这些字符串
void print_ksymtab_strings() {
printf("Symbol: %s\n", __kstrtab_init_mm);
printf("Symbol: %s\n", __kstrtab_start_kernel);
}
int main() {
print_ksymtab_strings();
return 0;
}
static const struct kernel_symbol __ksymtab_init_mm
__attribute__((__unused__))
__attribute__((section("__ksymtab"), unused))
= { (unsigned long)&init_mm, __kstrtab_init_mm };
__attribute__((__unused__))
和 __attribute__((unused))
是等价的,两者都用于防止编译器对未使用的变量、函数或参数发出警告。这两者仅用于告诉编译器“此变量/函数/参数可能未使用,不要发出警告”。
__attribute__((section("section_name"), unused))
: 这个属性组合同时指定了变量或函数的段以及标记其为未使用。具体地:
section("section_name")
:将变量或函数放入名为 section_name
的段中。
unused
:防止编译器对未使用的变量、函数或参数发出警告。