7
0
0

C语言

2026-08-25
2026-08-25
文章摘要
|

一、GCC扩展语法

1.语句表达式

#include<stdio.h>

void main(void)
{
    int a=({1;2;4;})+10;
    printf("%d\n",a);//a=14
}

这段代码中的 {1;2;4;}GCC 编译器提供的一个特殊扩展语法,叫做 语句表达式(Statement Expression)

  • 里面可以写多条正常的 C 语言语句。

  • 最关键的一点:整个语句表达式的值,等于最后一条表达式语句的值。

它最大的作用是把复杂的逻辑封装成一个表达式,常用于宏定义(Macro)中,避免宏参数被多次求值的问题。

例如下面的示例:

// 普通宏:如果传入 func(),func 会被执行两次!
#define MAX(a,b) ((a)>(b)?(a):(b)) 

// 使用语句表达式的宏:安全且能包含局部变量
#define MAX(a,b) \
    ({ \
        typeof(a) _a = (a); \
        typeof(b) _b = (b); \
        _a > _b ? _a : _b; \
    })

2.扩展关键字 typeof(a)

这个关键字是C 语言里的“类型推导器”:

typeof(x) y = 20; // 编译器看到后,等同于:int y = 20;

因此

typeof(a) _a = (a); //它的作用就是创造一个和A一样类型的变量

二、C语言中应该注意的地方

三、一些思路或方法

1.空指针偏移量计算

在 C 语言里,内存地址 0 是个很危险的地方。我们不是真的要去“碰”它,我们只是拿它当个“假想的起点”。所以 (struct st*)0 的意思就是:“假装地址 0 的位置,放了一个 struct st 结构体。

现在我想要测量这个结构体的b元素的位置,&((struct st*)0)->b,既然起点是 0,那你顺着往下找,找到 b 的位置,告诉我它距离起点 0 有多远(偏移量是多少)

看完上面的解释,应该知道下面这两个代码的功能是一样的。

typeof ((struct st*)0)->b) c; // 取b的类型来声明c
int c;

既然你能把结构体强转成 0 刻度(也就是 (struct st*)0),那如果现在要量的是个数组(比如 int 数组),你是不是也能用同样的方法,把数组强转成 0 刻度呢?

答:假设你有一个整型数组 int arr[10];,你想把它的首地址当成 0 刻度,你可以这样写:(int*)0

如果你想获取数组中第 3 个元素(即 arr[2])相对于 0 刻度的偏移量,你可以这样写:&(((int*)0)[2])

实际上上述操作就是Linux内核源码中的offsetof宏函数:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

C语言
/archives/cyu-yan
作者
Sharkey
发布于
2026-08-25
许可协议
CC BY-NC-SA 4.0

评论