十、 五种修饰函数的类型,typedef函数,宏定义,编译的过程,条件编译
1. const --》只读指针
1.修饰基本数据类型变量: const int a = 10; //修饰的变量必须初始化 //表示a为只读变量,不能修改 //a = 100; 编译会报错!!! 2.修饰指针变量: 第一种情况: int a=10, b =200; int * const p = &a; //必须初始化 p = &b; //编译会报错 *p = 300; //p指针解引用是可以的 第二种情况: int a=10, b =200; int const * p = &a; //必须初始化 p = &b; //可以 *p = 300; //p指针解引用编译会报错 第三种情况: int a=10, b =200; const int * p = &a; //必须初始化 p = &b; //编译会报错 *p = 300; //p指针解引用是可以的 第四种情况: int a=10, b =200; const int * const p = &a; //必须初始化 p = &b; //编译会报错 *p = 300; //p指针解引用编译会报错
2.volatile -->防止编译器优化变量
//单片机延时函数 void delay() { int i = 0x1000000; //可能会在编译时被编译器优化(删除)掉 while(i--); } //单片机延时函数 void delay() { volatile int i = 0x1000000; //编译器不会优化变量 while(i--); }
3.auto和register
1、auto自动化变量(内存变量),定义变量时可以省略不写 int a; <==> auto int a; 2、register(寄存器变量) --》用在调用频繁的变量可以定义成一个寄存器变量 register int a; --》变量定义时分配的寄存器存储 注意: 1》定义寄存器变量是不一定成功(主要看编译器),如果不成功他会自动定义成自动化变量 2》寄存器变量没有内存地址
4.extern
1、概念:表示外部调用,从其他.c文件里面调用 2、使用方法: 1》修饰变量 extern int a; -->从其他文件调用这个变量,如果其他.c文件没有定义肯定会报错 2》修饰函数 extern int add(int a, int b); -->表示当前.c没有定义该函数,在其他.c里面定义了该函数,如果其他.c文件没有定义肯定会报错 注意:static修饰的变量或函数,都是只能用于当前这个.c; 该变量不能再被estern调用!!!
5.typedef --》给数据类型取别名
1、给基本数据类型取别名 typedef int INT; //给int取了一个别名叫INT int a; 《===》 INT a; 2、给数组数据类型取别名 typedef int ARRAY[4]; //给数组类型为:int ()[4]取了一个别名叫做 ARRAY 3、给函数指针数据类型取别名 int add(int , int ); ---》对应的函数指针类型为:int (*)(int , int ); typedef int (*FUNC_P)(int , int ); //给函数指针int (*)(int , int )取别名叫FUNC_P 4》给结构体数据类型取别名 (1) 给结构体类型 struct student取了一个别名叫做STU,所以 struct student 《==》STU 1> struct student { char name[15]; int num; int age; char sex; }STU; 定义了一个结构体数据类型变量叫做STU 2> typedef struct student { char name[15]; int num; int age; char sex; }STU; //给结构体数据类型struct student 取了一个别名叫做 STU struct student lisi; ==》STU lisi; //都是表示定义结构体变量 struct student *p; ==》STU *p; //表示定义结构体指针 3> typedef struct student { char name[15]; int num; int age; char sex; }STU, *STU_P; //给结构体数据类型struct student 取了一个别名叫做 STU //给结构体数据类型struct student *(结构体指针)取了一个别名叫做 STU_P struct student lisi; ==》STU lisi; //都是表示定义结构体变量 struct student *p; ==》STU *p; //表示定义结构体指针 struct student *p; ==》 STU_P p; //表示定义结构体指针
6.宏定义(又称之为宏替换,在代码编译阶段中的预处理阶段进行替换,不是在程序运行的过程中替换)
1.宏定义变量 #include <stdio.h> #include <string.h> #define MUN 20 #define LCD_W 800 #define LCD_H 480 int main(int argc, const char**argv) { int arry[MUN]; printf("%d\n", sizeof(arry)); int lcd_len = LCD_H*LCD_W; printf("%d\n", lcd_len); return 0; } 注意:1》宏定义它是不需要分配内存 2》宏替换不能替换字符串里面的字符 2.带参宏 --》也是在编译阶段中的预处理阶段进行处理替换,它是和函数不同 带参宏与带参函数的5个区别: 带参宏 带参函数 处理时间 编译时 运行时 参数类型 无 需定义 程序长度 变长 不变 占用存储空间 否 是 运行时间 不占运行时间 调用和返回时占
7.编译的过程
把.c文件编译生成一个可执行文件,其实他是分为4个步骤:预处理、编译、汇编、链接 命令:gcc hello.c -o hello 1>预处理 预处理的编译命令: gcc -E hello.c -o hello.i 作用: (1)删除了注释代码 (2)展开了头文件 (3)处理了宏定义、带参宏、条件编译 2>编译 编译的编译命令: gcc -S hello.i -o hello.s 作用: (1)把C语言翻译成汇编语言 (2)检查代码语法错误 3>汇编 汇编的编译命令: gcc -c hello.s -o hello.o 作用: (1)把汇编语言翻译成机器码(二进制) 4>链接 编译命令: gcc hello.o -o hello 作用: 链接要用到的函数库,把函数库的静态库编译到可执行文件里面,动态库在你要执行时再调用
8.条件编译
条件编译--》有选择的编译,一般用于代码调试,也是在编译阶段中的预处理阶段进行处理 命令:gcc test5.c -o test5 -DNUM -->-D 表示定义宏,例如:-DNUM表示定义宏NUM!!! 1》 #ifndef -->if not define ,如果没有定义某个宏,就会把代码编译到可执行文件 #ifndef NUM //代码块 #endif 2》 #ifdef -->if define ,如果定义了宏,就会把代码编译到可执行文件 #ifdef NUM //代码块 #endif 3》 #if 如果为真就会把代码编译到可执行文件 #if 1 printf("hello world\n"); #else printf("good boy\n"); #endif #include <stdio.h> /***********************************************************************************/ 关于程序拆分 --》即把一个复杂的.c文件拆分为多个.c / .h文件 例子: 将project.c文件拆分为project.c、add.c和add.h三个文件。 //函数声明 int add(int a, int b); int reduce(int a, int b); int main(int argc, const char**argv) { int num = add(100, 200); printf("%d\n", num); int num1 = reduce(300, 100); printf("%d\n", num1); return 0; } int add(int a, int b) { return a+b; } 拆分效果: gec@ubuntu:/mnt/hgfs/C语言/11/code/test/test$ cat project.c -n 1 #include <stdio.h> 2 3 //函数声明 4 extern int add(int a, int b); 5 int reduce(int a, int b); 6 7 int main(int argc, const char**argv) 8 { 9 10 int num = add(100, 200); 11 printf("%d\n", num); 12 13 int num1 = reduce(300, 100); 14 printf("%d\n", num1); 15 16 return 0; 17 } gec@ubuntu:/mnt/hgfs/C语言/11/code/test/test$ cat add.c -n 1 #include "add.h" 2 3 4 int add(int a, int b) 5 { 6 return a+b; 7 } gec@ubuntu:/mnt/hgfs/C语言/11/code/test/test$ cat add.h -n 1 #ifndef __ADD_H__ 2 #define __ADD_H__ 3 4 //要包含的头文件 5 #include <stdio.h> 6 7 //宏定义 8 9 //结构体数据类型 10 11 //全局变量 12 13 14 15 16 //函数声明 17 int add(int a, int b); 18 19 20 #endif 编译命令: gcc project.c add.c -o project 注意:编译的时候要注意加上所有你需要运行的文件名!!! 执行文件:./project