美文网首页转载部分
c 语言几个特殊写法

c 语言几个特殊写法

作者: 守拙圆 | 来源:发表于2018-03-27 07:43 被阅读37次

    1 零长度和变量长度数组

    • 零长度数组
      GNU C 编译器允许使用零长度数组,在定义变长对象的头结构体时,这个特性非常有效,例如:
    struct var_data
    {
      int len;
      char data[0];
    };
    

    char data[0] 仅仅意味着程序中通过 var_data 结构体实例的 data[index] 成员可以访问len 之后的第 index 个地址,它并没有为 data[]数组分配内存,因此 sizeof(struct var_data) = sizeof(int)。

    假设struct var_data 的数据域就保存在 struct var_data紧接着的内存区域中,则通过如下代码可以遍历这些数据:

    struct var_data s;
    ...
    for(i = 0; i < s.len; i++)
        printf("%02x", s.data[i]);
    
    • 变量长度数组
      GNU C中也可以使用 1 个变量定义数组,例如如下代码中定义 double x[n]:
    int main(int argc, char **argv)
    {
      int i, n = argc;
      double x[n];
      for (i = 0; i < n; i++)
        x[i] = i;
      return 0;
    }
    

    2 宏定义语句表达式

    GNU C 把包含在括号中的复合语句看成一个表达式,成为语句表达式,它可以出现在任何允许表达式的地方。我们可以在语句表达式中使用原本只能在复合语句中使用的循环、局部变量等。例如:

    #define min_t(type, x, y) \
    ( { type __x = (x);  \
    type __y = (y);  \
    __x < __y? __x : __y; \
    })
    int ia, ib, mini;
    float fa, fb, minf;
    mini = min_t(int, ia, ib);
    minf = min_t(float, fa, fb);
    

    3 typeof 关键字

    typeof(x)语句可以获得 x 得类型,可以借助typeof重定义宏。

    #define min_t(x, y) \
    ( { typeof(x) __x = (x);  \
    typeof(x) __y = (y);  \
    __x < __y? __x : __y; \
    })
    

    4 可变参数宏

    标准c 就支持可变参数函数,意味着函数得参数时不固定得,例如printf() 函数得原型为:
    printf(const char *fmt, arg...);
    在 GNU c 中,宏也可接收可变数目得参数,例如:
    #define pr_debug(fmt, atg...) prink(fmt, ##arg)

    使用 ## 是为了处理arg不代表任何参数得情况,此时,前面的逗号就多余了,使用 ## 后,GNU预处理器会丢弃前面的逗号。

    5 标号元素

    标准 C 要求数组或结构体的初始化值必须以固定的顺序出现,在GNU C 中,通过指定索引或结构体成员名称,允许初始化值以任意顺序出现。

    指定数组索引的方法是在初始化值前加“[index] =”,当然也可以用 "[fisrt ... last]="的形式指定一个范围。例如:
    unsigned char data[MAX] = { [0 ... MAX - 1] = 0};

    结构体初始化,例如:

    struct test_t a =
    {
    .lseek = 1,
    .read = 2,
    };
    

    6 特殊属性声明

    GNU C 允许声明函数、变量和类型的特殊属性,以手动优化代码和定制代码检查的方法。要指定一个声明的属性,只需要在声明后添加 attribute((ATTRIBUTE)),其中 ATTRIBUTE 为属性说明,如果存在多个属性,则用逗号隔开。GNU C 共支持 noreturn、 format、section、aligned、packed等十多个属性。

    • noreturn 属性作用于函数,表示函数从不返回。这会让编译器优化代码并消除不必要的警告。例如:
    #define ATTRIB_NORET   __attribute__((noreturn))
    asmlinkage NORET_TYPE void do_exit(long error_code) ATTRIB_NORET
    
    • format 属性也作用于函数,表示该函数使用 printf,scanf 或 strftime 风格的参数,指定 format 属性可以让编译器根据格式化字符串检查参数。
      asmlinkage int printk(const char *fmt, ...) __attribute__((format (printk, 1, 2)));
    • unused 作用于未用到的函数或变量,用于消除编译警告。
    • aligned 作用指定变量、结构体、联合体的对齐方式,以字节为单位。
    struct example_struct 
    {
      char a;
       int b;
      long c;
    } __attribute__((aligned(4)));
    
    • packed 属性用于变量或结构体成员时表示最小可能的对齐,用于枚举、结构体或联合体类型时表示该类型使用最小内存。
    struct example_struct 
    {
      char a;
      int b;
      long b __attribute__((packed));
    };
    

    7 内建函数

    GNU C 提供了大量内建函数,其中大部分标准 C 库函数的 GNU C 库的内建版本,例如 memcpy() 等,它们与对应的标准 C 库函数功能相同。

    不属于标准库函数的其它内建函数的命名通常以 __builtin 开始,如下所示。

    • 内建函数 __builtin_return_address(LEVEL),返回当前函数或其调用者的返回地址,参数 LEVEL 用于指定调用栈的级数,如 0 表示当前函数的返回地址,1 表示当前函数的调用者的返回地址。

    注意:在使用 gcc 编译 c 程序的时候,如果使用 “-ansi -pedantic” 编译选项,则会告诉编译器不适用 GNU 的扩展语法。使用上述特性就会出现编译告警。

    相关文章

      网友评论

        本文标题:c 语言几个特殊写法

        本文链接:https://www.haomeiwen.com/subject/xnzeqftx.html