一.宏定义
程序运行步骤 : 源文件-->预处理-->汇编-->二进制-->链接(可执行文件)-->运行
1.宏定义
2.条件编译
3.文件包含
所有的预处理指令都是#开头
没有参数的宏定义的基本格式:
#define 宏名 值
宏定义的注意点:1.宏名和值之间一定要空格隔开 2.宏定义后面不要写分号 3.宏写在“”里面就不会替换
宏定义的规范:宏名要大写,kCount CONUT
宏定义是在代码翻译成0和1之前,把所有的宏名替换成后面的值
宏定义的作用域:默认从定义那行开始,一直到文件的结束.
* 可以手动的提前结束宏定义的作用范围 #undef
宏定义可以写在代码的任何位置, 跟注释一样
例如:
#define COUNT 6
int main()
{
int array[COUNT] = {1, 3, 4, 6};
for (int i = 0; i < COUNT; i++) {
printf("array[%d] = %d\n", i, array[i]);
}
return 0;
}
一.2.带参数的宏定义
#define SUM(v1, v2) ((v1)+(v2))
#define PF(v) ((v)*(v))
* 注意
1.()里面的参数不需要写参数类型
2.()和后面的替换的格式之间一定要有空格
* 带参数的宏和无参数的宏的区别
1.宏定义不会进行计算,你传给他什么,它就会替换成什么
2.带参数的宏效率比函数高一些,简单的运算,就用宏。复杂的用函数
3.宏 只是做一个简单的替换,不会运算
//定义一个宏,求三个数的最大值
#define MAX_VALUE(A,B,C) (A>B?A:B)>C?(A>B?A:B):C
//写一个带参数的宏,实现两个整数之间的交换
#define SWAP(a,b) {int c; c = a; a = b; b = c;}
//定义一个判断一个正数是否是偶数
#define TRUE 1
#define FALSE 0
#define EVEN(x) (((x)%2) == 0)?TRUE:FALSE
//定义一个宏,输出整型 浮点型
#define INTEGER(n) printf("%d\n", n)
二.static和extern对函数的作用
函数分为两种:
1.外部函数:
特点:定义的函数能被本文件和其它文件访问
>默认情况下,所有的函数都是外部函数,本文件和其它文件都能访问(调用)
>extern是完整的定义或者声明一个函数
>注意点:所有的外部函数不能重名
2.内部函数:
特点:定义的函数,只能在本文件访问
>内部函数在不同的文件中可以重名
extern对函数的作用:
1.完整的定义一个外部函数
2.完整的声明一个外部函数
static对函数的作用:
1.定义一个内部函数
2.声明一个内部函数(废物)
二.static和extern对变量的作用
"全局"变量分为两种:
外部变量:
特点:能在本文件和其他文件中访问,所有的同名外部变量都是使用同一块内存空间 (只有一个)
默认的情况下所有的全局变量都是外部变量
内部变量:
定义一个内部变量 用static 只能文件内部使用,别的文件访问不了。
注意:两个文件里,可以有重名的内部变量,但是互不影响
static int value;
extern 修饰全局变量,不是外部变量的意思,它是声明一个外部变量(类似函数声明),这个很特殊
static对变量的作用:
定义一个内部变量
extern对变量的作用:
声明一个外部变量
extern 只用来修饰全局变量
static 修饰局部变量的时候,会延长局部变量的生命周期
使用场景:如果一个变量调用的频率相当高,而且这个变量是一个固定不变的值,就可以用static来修饰。提高性能
三.typedef
typedef 就是用来对 数据类型 取外号
typedef的基本格式:
typedef 原类型名字 外号(新类型名称)
typedef 可以给原有的数据类型取外号,也可以给新的外号取外号
typedef int MyInt;
int main()
{
MyInt a = 15;
printf("%s\n",a);
return 0;
}
* 注意点:如果通过typedef给指向函数的指针取别名,指针的名称就是别名
typedef int * Mypoint
typedef - 结构体:
1.第一种方式,先定义结构提类型,再通过结构体类型名称取外号(新的数据类型)
struct Person
{
int age;
char * name;
};
typedef struct Person StrPerson;
StrPerson p = {44, "lee"};
2. 第二种方式,定义结构体类型和取外号 同时进行
typedef struct Person2
{
int age2;
char * name2;
} StrPerson2;
StrPerson2 p3 = {23, "tt"};
3.第三种方式, 对没有结构体类型名称的数据类型,取外号
typedef struct
{
int age;
int no;
} StrPerson3;
typedef - 枚举:
1.先定义一个枚举类型,再通过枚举类型名称来定义一个新的数据类型
enum Sex
{
kSexMan,
kSexWomen,
kSexYao
};
typedef enum Sex MySex;
2.在定义枚举类型的同时,取外号
typedef enum Sex2
{
kSexMan2,
kSexWomen2,
kSexYao2
} MySex2;
3.对省略枚举类型名称的枚举,取外号
typedef enum
{
kSexMan3,
kSexWomen3,
kSexYao3
} MySex3;
* 和用typedef定义结构体很像
typedef - 指向结构体的指针:
struct Student
{
int age;
char *name;
};
1.首先定义一个结构体类型,然后给指向结构体的指针取外号
typedef struct Student * StuPointer;
StuPointer stuP;
stuP = &stu;
stuP -> age = 40;
2.在定义结构体类型的同时,给指向结构体的指针取别名
typedef struct Student2
{
int age2;
char *name2;
} * StuPointer2;
StuPointer2 stuP2;
3.一般没人这样写,这种写法,没有办法定义一个结构体
typedef struct
{
int age3;
char *name3;
} *StuPointer3;
* typedef的作用:给现有的数据类型取外号(别名)
1.有利于加强数据类型的描述性
2.提高了程序的可扩展性,移植性
3.减少了代码的书写量,简化了代码
使用场合
1.给基本数据类型取外号
2.给指针取外号
3.给结构体取外号
4.给枚举取外号
5.给指向函数的指针取外号
6.给指向结构体的指针取外号
注意:typedef仅仅给原有的数据类型取一个别名,并不是真的创建了一个新的数据类型
四.typedef和#define的区别与注意点
#define 它仅仅是简单的替换,别的啥也没做(在代码翻译成0和1之前做)
typedef 是给我们原有的数据类型取一个新的外号
注意点:如果要用其它的名称来替换现有的数据类型,用typedef,不要用#define