GNU C扩展

语句表达式

一般一个()代表一个语句表达式;一个{}代表一个语句块,在{}中又可以包含表达式;
语句表达式的值是{}中最后一个表达式的值;
这种形式往往在宏定义中经常出现;

#include <stdio.h>

int main(void)
{
	int sum = 0;
	sum = ({
	int s = 0;
	for (int i = 0; i < 10; i++)
		s = s + 1;
	s;
	});
	printf(“sum: %d\n”, sum);
	return 0;
}

上面表达式sum的结果为10;

typeof

•作用:获取变量后者表达式的类型

int i;
typeof(i) j = 2;
int f(); 
typeof(f()) k;

函数的类型就是函数的返回值类型;

•基本用法

typeof (int *) y; 		//把y定义为指向int类型的指针;
typeof (int) *y; 		//把 y定义为指向int类型的指针;
typeof ( *x) y; 		//把y定义为指针x指向的数据类型;
typeof (int) y[4]; 		//相当于定义一个:int y[4];
typeof (+x) y[4]; 		//把y定义为指针x指向的数据类型的数组
typeof (typeof (char *)[4]) y; //定义一个字符指针数组:char *y[4];
typeof(int x[4]) y; 	//相当于定义:int y[4];

container_of

•获取结构体的首地址

struct student {
	int age;
	int num;
	int math;
} stu;

struct student *p = container_of(&stu.num, struct student, num);

指针p指向stu的地址,即通过stu的成员变量num,找到了该成员所在结构体的首地址

零长度数组

struct buffer {
	int len;
	char a[0];
};

适用不通场景下需要不同长度的buffer的情况;且零长度数组不占用空间,比用指针好

属性声明 _ attribute _((ATTRIBUTE))

适用 _attribute __来声明变量、函数的特殊属性,从而指导编译器进行特定方面的优化;

int global_val attribute((section(.data”)));

__ attribute __ (section(".text")) int func(void)
{
	return 0;
}

表示将变量 global_val 装载到.data数据段中,还可以装载到.text代码段或者自定义的section中;

同理将funch函数放在.text段中;

_ _ init宏

主要用于系统初始化的时候使用一次,后面无需使用,使用这个宏可以告诉内核对应的函数只使用一次,后续可以从内存中释放,这样可以节省内存。

static int __init arc_hl_init(void)
{
	pr_info(“ARC Hostlink driver mmap at 0x%p\n”, HOSTLINK);
	return misc_register(&arc_hl_dev);
}
#define __init __section(.init.text)

用__ init宏修饰的变量会放在.init.text段中,然后内核中的函数会负责进行清理;

aligned 用于指定结构体类型、联合类型、变量的地址对齐

char c2 __ attribute __((aligned(8))) = 4;

除了变量自然边界对齐外,还可以指定对齐方式,一般是2的幂次方;

packed

指定变量和类型(结构体、联合、枚举)使用最小可能的对齐

减少元素之间因边界对齐而造成的内存空间

format

format属性一般用来参数检查,一般多用于在打印中

__ attribute __ ((format (archetype, string-index, first-to-check)))
void LOG(const char *fmt,) __ attribute__ ((format(printf,1,2)))

LOG(“size;%d %d %f\n”, i,203.14);

告诉编译器,LOG按照printf格式来检查参数,1 代表格式化的参数"size;%d %d %f\n“; 2 代表从第几个参数开始,LOG中是从i开始的;

const

weak & alias

weak将强符号声明为弱符号,alias声明为别名;

void __ attribute__((weak)) func(void);
void f();
void f() __ attribute __ ((weak, alias(“__f”)))

constructor & destructor

用于构造函数和析构函数

_ attribute __ ((constructor)) int initfunc(void);
_ attribute __((destructor)) int exitfunc(void);

noinline & always_inline

内联函数:减少函数调用带来的开销 inline

used & unused

告诉编译器这个函数或者变量定义了但是没有用到,这样在编译的时候就不会产生告警信息,C语言中也可以在变量前面加void来达到相同的目的。

static __ attribute __ ((unused)) int a;
static int func(void) __ attribute __ ((unused));
int fun(__ attribute __ ((unused)) int a, int b);

int unused;
(void)unused;  //这样在编译的时候也不会产生告警信息

标号元素

int b[10]={
	[4] = 5,
};

通过标号给数组的某一个元素赋值

省略操作数的条件句

条件表达式中的中间操作数可以省略。那么如果第一个操作数为非零,则其值为条件表达式的值。

因此,表达式

x ? : y

如果x是非零值,则为x的值;否则,为y的值。
这个例子完全等同于

x ? x : y

在这种简单的情况下,省略中间操作数的能力并不是特别有用。当第一个操作数确定或可能(如果是宏参数)包含副作用时,它才变得有用。那么,重复中间的操作数将执行两次副作用。省略中间操作数会使用已经计算过的值,而不会产生重新计算的不良影响。

linux kernel中有多处这种类型的使用。详见这个链接
https://blog.csdn.net/u012028275/article/details/124523525

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值