c语言预处理指令、typedef、static和extern相关介绍
一:typedef
作用:可以给一个已经存在的数据类型取一个别名
格式:typedef 原数据类型 新类型 例如:typedef int INT;
预处理指令#define 也可以给数据类型取别用用法: #define INT int;
//1、用在基本数据类型上 int a = 10; typedef int TNT; typedef char CHAR; CHAR c='A'; //65 TNT b = 100; //2、给数组起别名 char ch[5]; typedef char NAME[20]; //用新的类型定义数组 NAME a1,a2; //char a1[20] char a2[20] //3、用在结构体上 //1)先定义结构,然后在定义新的类型 struct iPhone iphone5; struct iPhone *p; typedef struct iPhone IPHONE; IPHONE iphone6; IPHONE *p1; //2)定义结构体的时候,重新定义为一个新的类型 typedef struct Car{ int lunzi; }CAR; CAR car1; car1.lunzi = 80; printf("%d\n",car1.lunzi); //3)给一个匿名的结构体定义一个新的类型 typedef struct{ char *head; int data; char *next; }NODE; NODE h; //4、用在枚举类型上 //1)给一个枚举类型定义一个新的名称 typedef enum weekday{ one, two }WEEK; WEEK day; day = one; //2)给一个匿名的枚举类型,定义一个新的名称 typedef enum { three, four }WEEK1; WEEK1 day2; day2 = three; //3)用一个已经存在的枚举类型,定义一个新的类型 enum iColor{jin,bai,hei}; enum iColor c1; typedef enum iColor ICOLOR; ICOLOR c2; c2 = jin; //5、给函数指针起别名 int (*p8)(int a,int b); p8 = sum; int s1 = p8(56,23); typedef int (*ADD)(int a,int b); ADD p9; p9 = max; s1 = p9(34,88); printf("%d\n",s1); gets(a2); puts(a2);
二 :预处理指令
1)以 “#”开头
2)在编译之前做的一些处理
1>#include 文件包含指令
1)#include <系统头文件>
2) #include "自定义头文件"
作用:包含了系统或者用户自己定义的函数的声明,程序编译不会报错或警告,跟程序链接没有关系
完成了函数声明的拷贝。OC中不用#include因为它的头文件比较繁琐,还需要写条件编译指令(未来防止头文件的重复拷贝)
2>#define 宏定义
1】无参的宏定义: #define 宏名 字符串
注意:
1)宏定义,后面不用加分号
2) 当宏出现在字符串中的时候,不进行替换
3) 宏替换:在源程序中所有出现宏名的地方都替换成 宏定义的字符串
4) 宏定义的时候,注意一般情况下为了区分它和变量,一般是大写(棕色)
5)宏定义一般写到文件的开头,作用域从定义开始,到文件结束
如果提前碰到了 #undef 则宏就被取消了,下面的函数不能在使用宏了
#include <stdio.h> //无参数的宏 #define COLS 5 #define ROWS 10 #define M 3*y+y*y #define PI 3.14 #define ZC 2*PI*COLS #define INT int #define CAR struct Car #define P printf #define D "%d\n" #define F "%f\n" #define INT1 int * typedef int* PINT; //typedef要加分号 struct Car{ int lunzi; }; void test(){ printf("%f\n",ZC); } //取消宏定义 #undef ZC void test2(){ //printf("%f\n",ZC); } int main(int argc, const char * argv[]) { //1、宏的基本用法 printf("%d,%d\n",COLS,ROWS); //2、宏出现在字符串中 char *str="Hello world!,COlS\n"; printf(str); //3、宏替换 int y = 4; // 28*3 + 28*28 -28 // s = 3*y+y*y*3+3*y+y*y*3*y+y*y-3*y+y*y; int s=0; s = (3*y+y*y)*3+(3*y+y*y)*(3*y+y*y)-(3*y+y*y); //840 s = M*3+M*M-M; printf("%d\n",s); //284 //4、使用的宏,其中又包含了其他的宏 test(); //5、用宏可以定义新的变量 //int a INT a; a = 10; printf("a = %d\n",a); //struct Car car1={4}; CAR car1 ={4}; printf("lunzi = %d\n",car1.lunzi); //6、可以妙用宏,简化输出的代码 float f1 = 12.0f; P(D,a); P(F,f1); //7、关于typedef和#define的区别 int c=2,d=5; //int *p,q; //p指针,q就是一个int型 INT1 p,q; p = &c; q = &d; //q是整型的 //int *m;int *n; //int *m,*n; PINT m,n; m = &c; n = &d;
2】有参的宏定义
#define 宏名(形参列表) 字符串
注意:
1)在有参宏定义中,形参不需要指定类型
2)多个参数使用逗号分隔
3)有参宏定义的时候,注意宏名和括号之间不能有空格
宏定义都是完成了替换工作,不参与运算
3> 条件编译: 只编译满足条件的代码块条件编译:
形式一:
#if if
#elif else if
#else else
#endif }
形式二:
#ifdef M //如果定义了 M 就编译语句块1,否则编译语句块2
语句块1;
#else
语句块2;
#endif
形式三
#
三:利用条件编译打印调试信息
#include <stdio.h> #define DEBUG1 1 //0 程序上线,不能打印调试信息,1 开发模式 #if DEBUG1==0 // format 表示这是一个参数 ..可以多个参数 // ##表示可以没有参数 #define Log(format,...) printf(format,## __VA_ARGS__) #else #define Log(format,...) #endif void test(){ int a=10; Log("ssssss\n"); } int main(int argc, const char * argv[]) { test(); Log("xxxxx\n"); return 0; }
四:static 和extern的区别
一 extern对函数的作用 1> 完整的定义一个外部函数 2> 完整的声明一个外部函数 (默认情况下函数都是外部函数所有extern可以省略) static对函数的作用 1> 完整的定义一个内部函数 2> 完整的声明一个内部函数 二 static对全局变量的作用 static修饰的全局变量是内部变量 ,只能被本文件使用 三 static对局部变量的作用 而static修饰的局部变量会延长局部变量的生命周期,程序结束才会销毁,同时局部变量的作用域不会改变 四 static性能问题 static修饰的局部变量延长了它的生命周期,因此当一个函数被不断调用的话,其内部的局部常量内存中不会被不断分配销毁
五:static修饰的局部变量或全局变量在初始化前存在bss段,初始化后存放在数据段,