语句表达式
一般一个()
代表一个语句表达式;一个{}
代表一个语句块,在{}
中又可以包含表达式;
语句表达式的值是{}
中最后一个表达式的值;
这种形式往往在宏定义中经常出现;
#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,20,3.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