volatile:使编译器不进行该变量的优化
使用场景:
1.程序使用rtos,多线程都会读写的全局变量需要使用volatile
2.中断和主函数中都要读写的全局变量,需要使用volatile
3.单片机的寄存器定义需要使用volatile
const:用于修饰常量,以及修饰参数指明函数不会对参数进行更改,防止函数意外修改该参数,规避地址传递容易意外更改参数的副作用
其实根本来由是参数的值传递需要copy一份,这样如果结构体过大,那么值传递的效率很低,而地址传递不需要拷贝可以直接访问,效率很高,但是也容易出现意外修改地址里的值的情况,为了规避这个副作用,const就可以很好的规避这个问题
typedef:有利于程序的移植性
有效规避指针定义的缺陷:
实例
char *p1,p2;
这样p1是char *类型而p2是char类型
这就与我们想要的出现了偏差
我们可以用typedef来规避:
typedef char * PCHAR
PCHAR p1 p2;
这样的话p1,p2都是char *类型就符合了我们的预期
以及对于某些平台不支持long long类型,那么对于程序的移植就会出现巨大问题,typedef就能很好的规避这个问题
typedef long long LINT
如果平台不支持long long类型只需要把long long改为int之类的就行
void:修饰返回值与参数,void *无类型指针可以与任何类型的指针进行转换
我们可以写下面这样的函数:
print()
{
printf("this is print\n");
}
即没有写返回值类型也没有写参数类型列表,这在c语言里是被允许的,但这显然是一个很糟糕的程序
我们在主函数可以调用这个print()函数
int main(void)
{
print(12,32);
return 0;
}
print函数在定义时并没有加任何的参数列表,而在主函数我们调用它时加入参数,这样在c语言也是被允许的,但这样的参数是没有任何意义的,为了规范,void在参数和返回值上进行限制就可以很好的避免这种情况,毕竟如果运行结果不符合预期,但是这样不写参数和返回值类型又不会报错,定位错误的难度又上升了
void *常用于强转指针类型上
sizeof:注意sizeof的返回值类型是一个unsigned int类型
实例;
char arr[10];//显而sizeof(arr)是10
if((sizeof(arr) - 20) < 0)
//按道理10-20应该是-10<0,但现在其实是unsigned int 直接的减法,不可能小于0
printf(" < \n");
else
printf(" > \n");
输出结果为 >
再看下面这个实例:
int test(char arr[])
{
printf("%d\n",sizeof(arr));
}
char arr[10];
printf("%d\n",sizeof(arr));//结果为10
test(arr);//结果为4,原因是数组作为函数参数退化为指向数组首元素的指针
static:静态的,限定作用域,只初始化一次,生命周期为整个程序运行期间
static无论修饰全局还是静态变量都是存储在静态区,生命周期都是整个程序运行期间
static修饰局部变量:只初始化一次,与全局静态变量相比,局部静态变量仅限当前函数可见
static修饰函数:该函数的限定作用域为本源文件(.c文件)内,不可被外部链接
extern:声明为外部链接,即是全局的
extern int a;//声明a是外部链接的
int a;//定义a变量,会分配内存空间
extern int a = 1;//即声明a是外部链接又定义a变量,分配内存空间
extern void test(void);//声明函数是外部链接
头文件的作用也刚好是函数和变量的声明,因此我们在头文件经常extern各函数和部分的全局变量,声明可以多处声明,但是定义只能一次定义