< link type = "text/css" rel = "stylesheet" href = "https://files.cnblogs.com/eben-yl/shThemeDefault.css" /> < link type = "text/css" rel = "stylesheet" href = "https://files.cnblogs.com/eben-yl/shCore.css" />

eben_yl

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

在Linux内核代码中,有非常多的代码使用了GCC的很多扩展特性,本篇文章主要是对这些特性做一个小小的总结,代码全部来自于GCC手册


1.被一对花括号包起来的代码块可以作为一个表达式来使用,花括号中可以使用循环语句(while、for),开关语句(if、switch),本地变量等。代码如下:

1
2
3
4
({ int y = foo (); int z;
    if (y > 0) z = y;
    else z = - y;
    z; })

最后一条语句必须为一个表达式并以分号结束,该表达式既为该代码块的返回值用在其他语句或表达式中

1
2
#define maxint(a,b) \
({int _a = (a), _b = (b); _a > _b ? _a : _b; })

这样的宏定义比下面的代码在安全性上有很大的提高

1
#define max(a,b) ((a) > (b) ? (a) : (b))


2.申明本地标签(local label)

GCC允许在一个代码块中申明任何本地标签,但只能在申明的代码块中使用,具体语法如下

1
__label__ label1, label2, /* . . . */;

该语句仅仅申明了两个标签名,但没有定义标签本身,还需要使用标签名后接冒号(label:)的方式定义标签,本地标签一般在复杂的宏定义中使用比较有效,如果一个宏定义在一个函数中被多次展开(被多次引用),那么一个普通的标签就会出现重复定义的情况,而本地标签就能很好的避免该问题,例如如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define SEARCH(array, target) \
({ \
    __label__ found; \
    typeof (target) _SEARCH_target = (target); \
    typeof (*(array)) *_SEARCH_array = (array); \
    int i, j; \
    int value; \
    for (i = 0; i < max; i++) \
        for (j = 0; j < max; j++) \
            if (_SEARCH_array[i][j] == _SEARCH_target) \
                { value = i; goto found; } \
    value = -1; \
  found: \
    value; \
})


3.获取标签的值

可以获取一个标签的值(地址),标签的值得类型为void *,该值得类型为常量,可以用在任何需要改类型的地方,具体使用语法如下:

1
2
3
4
void *ptr;
/* . . . */
ptr = &&foo;//foo为一个标签
goto *ptr;

还可以这样用:

1
2
3
static const int array[] = { &&foo - &&foo, &&bar - &&foo,
                               &&hack - &&foo };
goto *(&&foo + array[i]);


4.内嵌函数

内嵌函数可以在它定义的地方访问任何可见的变量,我们暂且称包含内嵌函数的函数为containing_function,如果我们在内嵌函数中我们访问了containing_function的局部变量,那么我们在containing_function外部调用内嵌函数极有可能会引起混乱,后果如法预料。反之无论如何我们在containing_function内部调用该内嵌函数都是安全的,示例代码如下:

1
2
3
4
5
6
hack (int *array, int size)
{
    void store (int index, int value)
        { array[index] = value; }
    intermediate (store, size);
}

还可以在内嵌函数中使用在containing_function中定义的标签:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
bar (int *array, int offset, int size)
{
    __label__ failure;
    int access (int *array, int index)
    {
        if (index > size)
        goto failure;
        return array[index + offset];
    }
    int i;
    /* . . . */
    for (i = 0; i < size; i++)
        /* . . . */ access (array, i) /* . . . */
        /* . . . */
    return 0;
    /* Control comes here from access
    if it detects an error. */
  failure:
    return -1;
}


5.构造函数

在GCC编译器中有很多内置函数这些函数都已__buildin_开始,具体就不一一介绍。


6.typeof

如果我们需要一个类型,我们可以使用typeof,该操作符返回一个变量的类型。如果想要是你的程序兼容IOS C程序,那么可以使用__typeof__,示例代码如下:

1
2
3
4
#define max(a,b) \
    ({ typeof (a) _a = (a); \
    typeof (b) _b = (b); \
    _a > _b ? _a : _b; })

更多用法如下:

1
2
3
4
5
6
7
typeof (*x) y;
typeof (*x) y;
typeof (typeof (char *)[4]) y;//等同于char *y[4];
 
#define pointer(T) typeof(T *)
#define array(T, N) typeof(T [N])
array (pointer (char), 4) y;

在GNU C++中可以使用__auto_type


7.在条件表达式中省略操作数

如果在条件表达式(? :)中省略第一个操作数,那么如果条件为真那么该表达式的值既为条件的值,如下:

1
x ? : y//如果x不为0,那么该表达式的值为x


8.零长数组

零长数组在结构体的最后一个成员中非常有用,如下:

1
2
3
4
5
6
7
struct f1 {
    int x; int y[];
} f1 = { 1, { 2, 3, 4 } };
 
struct f2 {
    struct f1 f1; int data[3];
} f2 = { { 1 }, { 2, 3, 4 } };
1
2
3
4
5
6
struct foo { int x; int y[]; };
struct bar { struct foo z; };
struct foo a = { 1, { 2, 3, 4 } }; //合法
struct bar b = { { 1, { 2, 3, 4 } } }; //非法
struct bar c = { { 1, { } } }; //合法
struct foo d[1] = { { 1, { 2, 3, 4 } } }; //非法


9.不固定的初始化

自动变量的集合初始化不必需要常量表达式:

1
2
3
4
5
foo (float f, float g)
{
    float beat_freqs[2] = { f-g, f+g };
    /* . . . */
}


10.复合文字量

1
2
struct foo {int a; char b[2];} structure;
structure = ((struct foo) {x + y, ’a’, 0});

以上代码等价于:

1
2
3
4
{
    struct foo temp = {x + y, ’a’, 0};
    structure = temp;
}

再例如:

1
char **foo = (char *[]) { "x", "y", "z" };
1
2
3
static struct foo x = (struct foo) {1, ’a’, ’b’};
static int y[] = (int []) {1, 2, 3};
static int z[] = (int [3]) {1};

上面代码等价于:

1
2
3
static struct foo x = {1, ’a’, ’b’};
static int y[] = {1, 2, 3};
static int z[] = {1, 0, 0};


11.指定初始化

该特性是经常使用的特性:

1
int a[6] = { [4] = 29, [2] = 15 };

等价于:

1
int a[6] = { 0, 0, 15, 0, 29, 0 };

指定范围及结构体的成员指定:

1
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
1
2
3
4
5
6
7
8
struct point { int x, y; };
struct point p = { .y = yvalue, .x = xvalue };
struct point p = { y: yvalue, x: xvalue };
 
union foo { int i; double d; };
union foo f = { .d = 4 };
 
struct point ptarray[10] = { [2].y = yv2, [2].x = xv2, [0].x = xv0 };

未完待续......





posted on 2015-07-20 23:46  eben_yl  阅读(1385)  评论(3编辑  收藏  举报