1,内联函数
inline
内联函数和普通的函数相同,但是打开编译器优化选项时,内联函数和实质上不生成独立的代码,而是将代码直接嵌入到所要调用的地方去。这样做可以加快执行速度。一般与static连在一起使用,所使用的函数内容为尽量简短
eg
#include<stdio.h>
static inline void test()
{
printf("hi inline\n");
}
int main()
{
test();
return 0;
}
2,extern声明外部环境变量
通俗的讲就是把b.c的文件给a.c文件用
也可以声明函数,但函数声明默认本来就是外部使用的
在全局变量与局部变量,如果变量名字相同那么通常局部变量覆盖全局变量,而外部使用extern不影响
3,回调函数
直接通过函数指针来调用其他函数,然后直接把算好的数据保存在一个指针中,给到调用这个回调函数的位置。
eg:
#include<stdio.h>
void add(void *context,int a,int b)
{
int *result;
result=context;
*result=a+b;
}
void fun(void (*func)(void *context,int a,int b),void *context,int a,int b)
{
func(context,a,b);
}
int main()
{
int result;
fun(add,&result,3,2);
printf("%d\n",result);
return 0;
}
3,编译过程
c语言整个编译阶段有四个阶段:
1,预处理:代码中所有预处理语句得到处理,经过处理后,代码中就不再包含任何预处理语句
2,编译,把C语言代码转化为相应的机器的汇编代码
3,汇编,把汇编代码转化为机器指令,称为目标代码
4,连接,将一个或多个源代码生成的目标代码文件与系统提供的代码库相互连接形成可执行程序
4,宏#define与函数
在宏里面每一行都要有’',否者会报错
eg
#include<stdio.h>
#define swap_int(a,b) \
do { \
int tmp; \
tmp=(a); (a)=(b); (b)=tmp;\
}\
while(0)
int main()
{
int a=2;
int b=3;
printf("a=%d,b=%d\n",a,b);
swap_int(a,b);
printf("a=%d,b=%d\n",a,b);
return 0;
}
这里的do…while(0)意义为不会由于大括号小括号而影响到自己想要影响的顺序
5,代码分支
预处理可以根据指定条件,保留或去掉代码中的一些行
#include<stdio.h>
#if DEF==1
printf("haha");
#elif DEF==2
printf("yeye");
#else
printf("oo");
#endif
意为如果DEF==1则保留下面的代码,否则就不保留
#ifdef:用于判断一个宏是否被定义过,
#ifndef:用于判断一个宏是否未被定义过
6,枚举类型
语法:enum typeName{red,blue}color1;
枚举变量可以直接输出,但不能直接输入。如:cout >> color3; //非法
不能直接将常量赋给枚举变量。如: color1=1; //非法
不同类型的枚举变量之间不能相互赋值。如: color1=color3; //非法
枚举变量的输入输出一般都采用switch语句将其转换为字符或字符串;枚举类型数据的其他处理也往往应用switch语句,以保证程序的合法性和可读性
7,typeof获取数据类型
eg:
#include<stdio.h>
//#define max(type,x,y) ({ \
// type _x=x; \
// type _y=y; \
// _x>_y?_x:_y; \
// })
#define max(x,y)({ \
typeof(x) _x=(x);\
typeof(y) _y=(y);\
(void)(&_x == &_y);\
_x>_y?_x:_y;})
int main(void)
{
char i=8;
char d=10;
printf("%c\n",max(i++,d++));
return 0;
}
8,内核中container_of(ptr, type, member)的作用
type:结构体类型
member:结构体内的成员
ptr:结构体内成员member的地址
返回该结构体的一个类型
9,voliate的作用是作为指令关键字,确保本条指令不会因为编译器的优化而省略,而且要求每次从内存中直接读取值。
10,在gnu C中对数组的特定的值进行赋值
#include<stdio.h>
int main()
{
int b[100]={[10]=1,[20]=2};
printf("%d\n%d\n",b[10],b[20]);
int c[100]={[10 ... 30]=6666,[50 ... 60]=2};
for(int i=10;i<=20;i++)
{
printf("%d\n",c[i]);
}
for(int i=50;i<=60;i++)
{
printf("%d\n",c[i]);
}
return 0;
}
11、’…‘ 表示范围扩展,在swich case里面也能使用
#include<stdio.h>
int main()
{
int i=4;
switch(i)
{
case 1:
{
printf("1\n");
break;
}
case 2:
{
printf("2\n");
break;
}
case 3 ... 5:
{
printf("3to5\n");
break;
}
default:
{
printf("default");
break;
}
}
return 0;
}
12、type和typeof的用法
type在这里获取传去的类型
typeof在这里获取表达式或则变量的类型
#include<stdio.h>
#define MAX1(x,y) x>y ? x:y
#define MAX2(x,y) ((x)>(y) ? (x):(y))
#define MAX3(x,y) ({ \
int _x=x; \
int _y=y; \
_x > _y ? _x : _y; \
})
#define MAX4(type,x,y) ({ \
type _x=x; \
type _y=y; \
_x > _y ? _x : _y; \
})
#define MAX5(x,y) ({
typeof _x=x; \
typeof _y=y; \
(void) (&_x == &_y); \
_x > _y ? _x : _y; \
})
int main(int argc,int **argv)
{
printf("%d\n",MAX5(2,3));
return 0;
}
13、零长度数组的用法
通常是和结构体一起使用,构成变长结构体:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct buf{
int len;
char a[0];
};
int main()
{
struct buf *buff=(struct buf *)malloc(sizeof(struct buf)+30);
buff->len=30;
strcpy(buff->a,"hello hello");
printf("buff->len:%d\nbuff->a:%s\n",buff->len,buff->a);
return 0;
}
14、attribute((Attribute)):主要用来指导编译器在编译程序时进行特定的方面代码的优化或代码检查。有7个分别是:
section:在程序编译时,将一个函数或变量放到指定的段,即放到指定的section中,一般有代码区,数据区,bss区。代码段(.text)函数定义、程序语句。(.data)初始化的全局变量,初始化的静态局部变量。(.bss)未初始化的全局变量,未初始化的静态局部变量。
aligned:指定一个变量或类型的对齐方式。
packed:一般用来减少地址对齐,指定变量或类型使用最可能小的地址对齐方式。
format,weak,alias,noinline,always_inline
#include<unistd.h>
#include<stdio.h>
/*struct student
{
int a;
short c;
char b;
} __attribute__((packed,aligned(8)));
*/
struct student
{
int a;
short c;
char b;
} __attribute__((packed));
int main(int argc,char* argv[])
{
int c2 __attribute__((aligned(8))) = 4;
static char c3 __attribute__((section(".data")))='a';
struct student stu1;
printf("%d\n",sizeof(stu1));
return 0;
}