GCC特性和选项
- GNUC 版本要求判定
#if defined __GNUC__ && defined __GNUC_MINOR__
# define __GNUC_PREREQ(maj, min) \
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
#else
# define __GNUC_PREREQ(maj, min) 0
#endif
#if __GNUC_PREREQ(3, 3) // 要求版本是3.3 以上
...
#endif
- GNUC 版本整数转换
/* gcc version. for example : v4.1.2 is 40102, v3.4.6 is 30406 */
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
-
编译选项
- 编译过程选项,解释、汇编、编译
-E
、-S
、-c
- 开启/关闭
no_instrument_function
属性-finstrument-functions
-fno-instrument-functions
- 仅进行词法与语法的分析
-fsyntax-only
- 遵循某种编码标准,比如不允许混合声明变量
-std=xxx -pedantic-errors
- 优化选项,分四级(默认为0),越大越优化;s选项只对目标文件大小进行优化,可能会影响性能
-O[0123s]
- 警告
-Werror
警告都是错误,无法通过编译-Wall
显示所有警告-Wnonnull
显示标记nonnull
属性的不符合规则的函数的警告
- 编译过程选项,解释、汇编、编译
-
链接选项
- 开启或关闭链接所有
.o
或.a
中的符号,可以同时使用-Wl, --whole-archive
-Wl, --no-whole-archive
- 反复搜索标示之间的所有.o或.a中的符号
--start-group <static-library/archives> --end-group
- 编译生成函数与函数地址的映射表文件
-Wl,-Map=test.map
- 导出目标的所有符号,用于程序在引用的动态库中调用属于自己的函数
-Wl,-E
等效--export-dynamic
等效-rdynamic
- 指定编译和运行时,动态库的优先搜索位置
-rpath<path>
- 静态链接静态库
-static
- 开启或关闭链接所有
-
内建函数
size_t __builtin_offsetof(type, member)
静态编译时获取type
中成员member
的偏移字节数。扩展#define offsetofend(TYPE, MEMBER) (offsetof(TYPE, MEMBER) + sizeof(((TYPE *)0)->MEMBER))
获取type
中成员member
结束位置的偏移字节数。void *__builtin_return_address(level)
获取函数调用栈的函数地址,0表示当前函数。bool __builtin_constant_p( exp )
如果表达式是常量(字面量),则返回true。- 静态分支预测
- 通过这种方式,编译器在编译过程中,会将可能性更大的代码紧跟着起面的代码,从而减少指令跳转带来的性能上的下降
bool __builtin_expect(!!(exp), 1)
分支预测,大部分表达式都为真bool __builtin_expect(!!(exp), 0)
分支预测,大部分表达式都为假
bool __builtin_types_compatible_p(typeof(x), typeof(y))
判断变量x
和y
的类型是否相同,相同返回 真,不相同返回 假。unsigned long long __builtin_bswap64(unsigned long long)
交换8字节,用于大小端转换。unsigned int __buildin_bswap32(unsigned int)
交换4字节。unsigned short __buildin_bswap16(unsigned short)
交换2字节。unsigned int __builtin_popcount(word)
返回被设置为1的位数void __builtin_prefetch( const void *addr, int rw, int locality )
预提取。addr
为预提取的内存地址;rw
为1,则表示为写而预提取,否则为读;locality
为1,则在使用数据后还缓存在cacheline中,否则清除缓存。可以没有rw
,或没有rw
和locality
参数。比如__builtin_prefetch(x)
仅为读预提取;__builtin_prefetch(x,1)
仅为写预提取。
-
类型操作
typeof(exp)
得到表达式的类型,sizeof(exp)
得到表达式的大小- 比如
#define min(x, y) ({typeof(x) _x = (x); typeof(y) _y = (y); (void)&_y == &_x; _x > _y ? _y : _x})
内核使用此宏得到最小值 - 比如
typeof(1 + 2UL) size = 1L;
- 比如
unsigned long size = sizeof(1 + 2L);
-
函数或变量属性
__attribute__((attr1),(attr2),...)
可以有多个属性,如果函数声明和定义分开,那么请将属性放置在定义处的函数名字前。void __attribute__((noreturn)) func();
不会返回值void __attribute__((nonnull(1, 2))) func( void *ptr1, void *ptr2 );
给出一个数字列表,指示函数中哪些形参不会为NULL
,且可以和-Wnonnull
关联,如果实参在编译时为NULL
,则发出警告。void __attribute__((alias("myfunc"))) func();
指定 func 别名为 myfunc,一般与weak
属性一起使用。比如write()
的别名为__write()
,即如果找不到func
符号 就使用myfunc
代替。GNU汇编为asm(".set func myfunc\n\t")
。void __attribute__((weak)) func();
指定func是一个弱定义,当有两个函数同名时,则使用强符号(也叫全局符号)来代替弱符号,通常与alias
属性一起使用。GNU汇编为asm(".weak func\n\t")
。void __attribute__((constructor(PRIORITY))) func();
func会按优先级升序在进入main函数前调用void __attribute__((destructor(PRIORITY))) func();
func会按优先级降序序在main函数返回后调用void __attribute__((noinline)) func();
func不能作为inline函数优化void __attribute__((section("specials"))) func();
将func放到specials段中,而不是通常的text段中,该属性也可以作用与变量或常量。void __attribute__((deprecated)) func();
将func函数声明为已废弃函数,如果被使用则将发出编译警告void __attribute__((__used__)) func();
告诉编译器,告诉编译器无论调用与否都必须链接该函数,该属性也可以作用于变量或常量。int __attribute__((__const__)) func(int);
函数没有内部状态,仅使用入参或常量(字面量)进行工作。int __attribute__((warn_unused_result)) func();
如果调用者没有使用返回值,则发出编译警告。void __attribute__((no_instrument_function)) func(void*, void*);
所有普通调用在进入和离开时调用一个特殊的指定函数- 进入函数主动调用(
func_address
被调函数地址,call_site
调用函数地址;需要自己实现 )
void __attribute__ ((no_instrument_function)) __cyg_profile_func_enter( void *func_address, void *call_site );
- 离开函数主动调用
void __attribute__ ((no_instrument_function)) __cyg_profile_func_exit ( void *func_address, void *call_site );
- 进入函数主动调用(
decl type __attribute__((aligned(x)));
定义一个按指定大小x
对齐的类型或变量struct T {...} __attribute__((aligned(32)));
结构体对齐struct T {char c, int i[32] __attribute__ ((aligned(32)));};
结构体字段对齐
decl type __attribute__((packed));
定义紧凑模型的类型或变量struct T { char c, int i; } __attribute__((packed));
这个类型的的大小就是各个字段类型大小的和为 5 bytes。
decl type __attribute__((aligned(cache_line)));
缓存线对齐void inline __attribute__((always_inline)) func();
强制内联函数- 如果不强制内联,函数不会被编译器自动内联的规则如下:
- 变参数函数
- 含调用
alloca
类库函数 - 含有可变尺寸数组声明函数
- 含非本地
goto
函数 - 递归调用函数
- 如果不强制内联,函数不会被编译器自动内联的规则如下:
-
匿名联合
struct T { union { int a, char b }; int c; }; T t = { .b = 'a', .c = 10, };
-
零长数组
- 结构体后跟变长数据,但
sizeof()
运算不包含边长部分。例子中的offset被定位到结构体后变长数组的最后一个元素。
- 结构体后跟变长数据,但
typedef struct { int a; char b; short c[2]; char next[0]; } T;
T *t = (T*)malloc(sizeof(struct T) + sizeof(T*) * 3);
T **offset = (T**)&t->next;
offset[2] = t;
-
范围扩展
switch/case
语句:int x = 5; switch(x) { case 0: ; case 1 ... 5: ; default:; }
- 数组定义:
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
-
关键字
__alignof__(deftype)
获取deftype
定义类型的对齐大小。__typeof__(var/deftype)
获取var
变量(值)的类型或deftype
定义类型的类型。比如 :typeof(int [10]) a1, a2;
等效int a1[10], a2[10];
。
-
宏函数
- gcc 支持 使用
#define macro(...) ({ ... })
定义宏函数。 __label__
关键字用于定义块内跳转,比如#define macro(...) ({__label__ out; int ret = 0; if (...) goto out; else {...} out: ret;})
- gcc 支持 使用