gcc扩展学习总结

       

       (一)语句表达式

       语句表达式就我看来就是对宏定义的扩展,不过呢看起来又有点像函数,简单说来就是将括号中的复合语句看成一个表达式,在这些复合语句中可以使用循环,判断,局部变量等,其中复合语句的最后一个以分号结束的字句的值就是整个表达式的结果。

       求最大值可能通常会定义如下:

      #define max(x,y) ((x)>(y) ? (x) : (y));

     对于简单的变量x,y,改语句应付自如,可是如果x,y本身不简单呢?该语句要么计算2次,要么它会产生错误的输出,其原因太简单了,就不总结了。

       通过gcc的扩展可以很容易解决上述语句所带来的烦恼,在内核代码kernel.h中对求最大值的定义如下

                   #define max(x,y)({typeof(x)  _x =(x);   typeof(y) _y=(y); (void) (&x ==&y); _x >_y ?_x :_y })

     看到这里,相信有一些程序基础的人都能明白其中的奥妙了吧,说多了都是眼泪,是爷们的你自己去品味吧!

 

       (二)零长度数组   

        它基本的结构如下:

             struct A {

                            int id;

                             XXX bytes[0];

                              };

         它可以动态的增加数组的长度,最后一个元素是零长度数组,他不占用结构体的空间,当使用malloc为bytes分配空间后,bytes指向所分配空间的首地址,且这个首地址紧接着结构体的地址,换句话说零长度数组的长度可以按需分配,我在学习时所写的示例如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


 typedef struct ArrayStruct{
  int id;
 char bytes[0];
}ARRAY;


int main(void)
{
   ARRAY *test;
   int length=20;
  test=(ARRAY *)malloc(sizeof(ARRAY)+length);
  memset (test->bytes,0,length);
  memcpy(test->bytes,"xiaoweibeibei",sizeof("xiaoweibeibei"));
  printf("the value of the bytes is :%s/n ",test->bytes);

  free(test);
 
}

运行该程序输出是:

the value of the bytes is :xiaoweibeibei
    (三) 可变参数宏

这个东东在驱动代码中常常见到,他可以定义参数可变的宏,它是宏的定义更加具有灵活性,常见的形式如下:

       (1)#define debug(format,...) fprintf(stderr,format,_VA_ARGS_)

       (2)#define debug(format,args...)  fprintf(stderr,format,args)

       (3)#define debug(format,args...) fprintf(stderr,format,##args)

其中,(1)在实际调用时 “...”会代替宏体里的_VA_ARGS_。对于(2)和(3 )的共同点在于它们为可变参数起了个名字,它们的区别在于如果传递空参数时的不同。例如对于(2)在调用debug("xiaoweibeibei")时会,宏展开后会多一个逗号,而对于(3)将会把这个逗号去除掉。

      (四)标号元素

        如果没有标号元素估计我不会想到去看gcc的扩展语法,估计也会和任哥的大作失之交臂,呵呵~

        标号元素的作用在于可以在数组或结构体的初始化过程中可以不以固定的顺序出现,它通过使用数组的索引或结构体的结构域名来进行无序的初始化。具体示例如下:

#include <stdio.h>
typedef struct array{
   int id;
   int length;
   int max;
   int min;
   char name[10];
} ARRAY;

int main(void){
int a[10]={ [4]=5,[5]=7};
ARRAY test={
 .min=7,
 .max=4,        
};
printf("test.id=%d/n",test.id);
printf("test.length=%d/n",test.length);
printf("test.max=%d/n",test.max);
printf("test.min=%d/n",test.min);
printf("test.name=%s/n",test.name);
int i;
for( i=0;i<10;i++){
  printf("a[%d]=%d/n",i,a[i]);
}
}

他的好处也是显而易见的,就上例而言,如果把代码该成如下形式:

    int a[10];

    a[4]=5;a[5]=7;

程序运行是没有问题的,可是如果在仔细研究就会发现,其实你在定义数组的时候,编译器就会为你的每个元素赋了其默认值0(可以通过打印出来测试),那么程序在执行a[4]=5;相当于把a[4]的值又赋值成了5。也就是说在这个过程中为了达到你想要的结果a[4]=5,要执行2次,对比采用标号元素,不用多说,其好处是显而易见的。

(四) 特殊属性和内建函数

在任哥的大作《linux内核修炼之道》中还介绍了特殊属性和内建函数,关与这些我个人觉得没有什么总结的必要,在这里就简单的写下,留着备忘。

  特殊属性是指gcc可以允许变量、函数、类型的特殊属性,通过申明这些特殊属性可以使编译器在编译时候进行一定的优化和代码检查;对于内建函数大部分是针对对C库函数的内建版本,起名字常常以_builtin开头。

  对于特殊属性和内建函数,个人觉得只要知道有这个概念就可以了,如果在以后读代码或写代码时候遇到了,通过查相关的gcc手册很容易就搞定~

 

 

               

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值