GCC 对 C 语言的扩展

发布于:2025-09-12 ⋅ 阅读:(17) ⋅ 点赞:(0)

大家好!我是大聪明-PLUS

GNU 编译器集合 (GCC) 提供了 ISO 标准 C 中没有的几种语言功能。

在我撰写本文时,GCC 拥有超过60个不同的拓展,它们可以改变 C 语言(以及 C++)的行为或添加功能。其中一些扩展非常有趣,另一些则有点令人困惑,还有一些则有些危险!

了解这些 GCC 扩展非常重要,因为其中许多扩展被多个免费和开源项目使用,包括 Linux 内核。

让我们来看看其中的一些吧?

嵌套函数

GCC 允许声明嵌套函数(在另一个函数内部定义的函数)。

嵌套函数的名称将是其定义块的本地名称,并且可以访问其定义点可见的包含函数的所有变量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include 

int main(int argc, const char *argv[])
{ void p (void) { printf("Inside a nested function!n"); } p(); return 0;
}
$ gcc nested.c -Wall -Werror -o nested
$ ./nested
Inside nested function!

typeof 关键字

我们可以使用typedef关键字来引用表达式的类型,从而可以在 C 中进行泛型编程!

例如,下面的max(a,b)宏可对任何算术类型进行操作:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include 

#define max(a,b) 
 ({ typeof (a) _a = (a); 
 typeof (b) _b = (b); 
 _a > _b ? _a : _b; })

int main(int argc, const char *argv[])
{ int x = 1024, y = 4096; char a = 10, b = 20; float j = 1.0, k = 2.0; printf("char max is %dn", max(a,b)); printf("int max is %dn", max(x,y)); printf("float max is %fn", max(j,k)); return 0;
}
$ gcc typeof.c -Wall -Werror -o typeof
$ ./typeof
char  max is 20
int   max is 4096
float max is 2.000000

空结构

GCC 允许 C结构没有成员(结构的大小为零)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include 

struct empty {
}; int main(int argc, const char *argv[])
{ printf("sizeof struct empty is %ldn", sizeof(struct empty)); return 0;
}
$ gcc empty.c -Wall -Werror -o empty
$ ./empty
sizeof struct empty is 0

在 C++ 中,空结构是语言的一部分。

案例范围

在 GCC 中,我们可以在单个case标签中以"case start ... end ”的格式指定一系列连续的值。很疯狂吧?

这与适当数量的单独案例标签具有相同的效果,从startend(含)的每个整数值对应一个标签。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include 

void ranges(char c)
{ switch(c) { case '0' ... '9': printf("[%c] is a number.n", c); break; case 'a' ... 'z': printf("[%c] is a lowercase letter.n", c); break; case 'A' ... 'Z': printf("[%c] is an uppercase letter.n", c); break; default: printf("[%c] is not a valid character!n", c); break; }
} int main(int argc, const char *argv[])
{ ranges('a'); return 0;
}
$ gcc ranges.c -Wall -Werror -o ranges
$ ./ranges 
[a] is a lowercase letter.

零长度数组

GCC 允许声明零长度数组。

零长度数组可以用作结构体的最后一个元素,例如,用作可变长度对象的标头。在这种情况下,零长度数组的名称可以用作指向动态分配对象的指针。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include 
#include 

struct msg_header { int type; int size; char content[0];
}; int main(int argc, const char *argv[])
{ struct msg_header *msg; int size = 1024; msg = (struct msg_header *) malloc(sizeof (struct msg_header) + size); msg->type = 0x01; msg->size = size; printf("msg header is at %pn", (void *)msg); printf("msg content is at %pn", (void *)msg->content); return 0;
}
$ gcc array.c -Wall -Werror -o array
$ ./array
msg header  is at 0x55c428265260
msg content is at 0x55c428265268

还有许多其他扩展,但是我们真的应该使用它们吗?

我们应该使用 GCC 扩展吗?

所有示例均使用 GCC 7.4.0 编译。

这些扩展无需任何额外的编译器标志即可使用,因为默认情况下 GCC 7.4 使用-std=gnu11进行编译,这意味着支持 ISO C11 标准和 GCC 扩展。

虽然其中一些扩展确实很有用,但其代价是可移植性。使用 GCC 扩展,我们可能会在使用其他编译器构建程序时遇到问题。

例如,Clang有自己的一组扩展,并且不支持所有 GCC 扩展,如嵌套函数。

$ clang nested.c -o nested
nested.c:5:19: error: function definition is not allowed here
    void p (void) { printf("Inside a nested function!n"); }
                  ^
nested.c:7:5: warning: implicit declaration of function 'p' is invalid in C99 [-Wimplicit-function-declaration]
    p();
    ^
1 warning and 1 error generated.

如果您想知道是否正在使用任何 GCC 扩展,请启用-pedantic编译器选项来生成警告或启用-pedantic-errors编译器选项来生成错误。

$ gcc arrayzero.c -o arrayzero -pedantic-errors
arrayzero.c:7:7: error: ISO C forbids zero-size array ‘content’ [-Wpedantic]
  char content[0];
       ^~~~~~~

并且,如果您想使用 GCC 扩展并仍保持程序的可移植性,则可以使用宏__GNUC__进行条件编译来测试这些功能的可用性,该宏始终在 GCC 下定义。

GCC文档中提供了 C 语言的 GCC 扩展的完整列表。

现在来个挑战吧!你能通过阅读源代码,找到下面程序中使用的两个 GCC 扩展吗?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include 

int main(int argc, const char *argv[])
{ int a = 10; int x = 0; a = x ? : 0b0010; printf("a is %d.n", a); return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到