13.C基础_预处理

预处理语句就是以#开头的语句。这些语句类型如下:

  • #include:包含头文件
  • #define:宏定义
  • #undef:取消宏定义
  • #ifdef,#endif:成对使用,判断是否定义了某个宏

宏定义

宏定义的本质就是原样替换,写什么值就替换成什么。

形式:#define 名字 值

 1、示例使用

示例1:基本使用

#define PI 3.14
printf("%d",PI);//这实质就是执行printf("%d",3.14);将PI用3.14替换

示例2:利用宏定义中的值是其他的宏

#define a 1
#define b 2
#define c (a+b)//使用宏来充当值
printf("%d",c);//这实质就是执行printf("%d",(1+2));

示例3:宏定义实现代码开关

#define DEBUG//用作开关时,后面不跟值

#ifdef DEBUG
    printf("DEBUG");//如果宏定义了DEBUG,就执行这个语句
#endif
/* #ifdef 与 #endif 配对出现*/

示例4:改变宏定义的值

#define a 100
/* ...一些代码 */
#undef a //取消a的宏定义
#define a 200//重新定义a为200

示例5:传参数的宏

#define MAX(a,b) ((a)>(b)?(a):(b))

/* 调用 */
MAX(1,2)//即a=1,b=2,这实际就是((1)>(2)?(1):(2))

2、注意点

注意点1:当宏定义的值为表达式时,需要加括号

#define N (3+2) //这里不能写3+2,必须写(3+2)

 注意点2:宏定义的名称不能与函数名重复

注意点3:宏定义传参时,后面的值需要加括号

下列代码test2应该写为((n)*(n)) ,因为n*n也可能因为其他高优先级的情况被拆开。

3、宏定义与常量const的区别

1.1 定义不同

宏用 " #define " 声明,const 常量用 " const + 数据类型 " 声明

宏最后没用分号,const 常量声明需要用分号表示语句结束

宏不需要用等号赋值,cosnt 常量需要用等号赋值

1.2 处理阶段不同

宏定义在预处理阶段进行文本替换,const 常量在程序运行时使用。

1.3 存储方式不同

宏定义是直接替换,不会分配内存,存储于程序的代码段中。const 常量需要进行内存分配。

1.4 是否进行类型检查

宏定义是字符替换,不进行类型检查。

const 常量定义时需要声明数据类型,使用时会进行类型检测

1.5 其他

宏定义可以声明函数,也可以用undef取消宏

4、宏定义与typedef的区别

2.1 定义不同

typedef 是 C语言的关键字,用于创建类型别名,它需要使用标 识符和现有的类型进行配合

#define 是预处理指令,用于创建宏定义,它可以定义任意的标识 符和文本替换

2.2 处理阶段不同

关键字typedef在编译阶段有效,有类型检查的功能

#define则是宏定义,发生在预处理阶段,也就是编译之前, 它只进行简单而机械的文本替换,而不进行任何检查

2.3 定义变量时的含义不同

例如有以下声明:

typedef int* Pint16_t;
#define Pint16_t int*

这两种声明都是把int*用Pint16_t来替换。但定义变量时的含义不同:

/* typedef的含义 */
Pint16_t p1,p2;//这代表p1,p2都是int*类型

/* #define的含义 */
Pint16_t p1,p2;//这代表p1是int*型,p2是int型

代码验证如下: 

2.4 作用域不同

typedef 有作用域限定。如果放在所有函数之外,它的作用域就是从它定义开始直到文件尾; 如果放在某个函数内,定义域就是从定义开始直到该函数结尾

 #define 不受作用域约束,只要是在 #define声明后的引用都是正确的,不管是在某个函数内,还是在所有函数之外,作用域都是从定义开 始直到整个文件结尾。

5、宏定义传参与函数的区别

宏在调用时的效率是比函数高很多的;

函数的参数是有类型的,也存在类型检查。但宏的参数是没有类型与类型检查的;

函数可以递归,而宏不可以递归;

函数方便调试,而宏是不方便调试的;

对于参数而言,宏的参数是直接替换的,所以会有一些参数具有副作用。而函数的参数是临时拷贝的,没有副作用的情况;

#include的<>与" "的区别

#include <xxx.h>与#include "xxx.h"的区别是搜索路径不同:

  • <>:编译器到标准库路径下寻找头文件,路径为/usr/include
  • " ":编译器先在当前文件下寻找头文件,找不到时再去标准库寻找头文件

别名typdef

1、别名基本类型

基本类型有char、int、float、double这些。

形式:typdef <类型> <别名>;

如:typdef unsigned char uint8_t,这表示uint8_t就是unsigned char

2、别名基本指针

基本指针有char*、int*、float*、double*这些

形式:typdef <指针> <别名>;

如:typdef int* PData,定义时可以用 " PData a; "来代替 " int* a; "这样使用。

别名指针后,定义指针不需要写*,类型是PData,而不是PData*

3、别名结构体

形式:

typedef struct 结构体名{
    //结构体成员
}结构体别名,*结构体指针别名;

/* 举例 */
typedef struct test{
    int a;
    int b;
}Name,*PName;

在上述举例中,是用Name作为struct test的别名,PName作为指针别名

4、别名数组指针

数组指针的定义是:<类型> (*指针名)[列大小]

别名形式就是把指针名换为别名:typedef <类型> (*别名)[列大小]

5、别名函数指针

函数指针的定义是:<返回值类型> (*指针名)(形参)

别名形式就是把指针名换为别名:typedef  <返回值类型> (*别名)(形参)

  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值