GCC特性笔记

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 --end-group
    • 编译生成函数与函数地址的映射表文件
      • -Wl,-Map=test.map
    • 导出目标的所有符号,用于程序在引用的动态库中调用属于自己的函数
      • -Wl,-E 等效 --export-dynamic 等效 -rdynamic
    • 指定编译和运行时,动态库的优先搜索位置
      • -rpath
    • 静态链接静态库
      • -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)) 判断变量 xy 的类型是否相同,相同返回 ,不相同返回
    • 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,或没有rwlocality参数。比如__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();强制内联函数
      • 如果不强制内联,函数不会被编译器自动内联的规则如下:
        1. 变参数函数
        2. 含调用 alloca 类库函数
        3. 含有可变尺寸数组声明函数
        4. 含非本地 goto 函数
        5. 递归调用函数
  • 匿名联合

    • 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)