7
0
0
C语言
文章摘要
|
一、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)