C语言预处理

预定义符号

__FILE__                获取文件名

__LINE__               获取行号

__DATE__              获取日期

__TIME__               获取时间

__FUNCTION__     获取当前函数名
__STDC__              遵循ANSI C,值为1;不遵循,未定义

        可以跟文件指针搭配,写成日志,项目中,日志可以快速查到程序错误和异常的地方,方便调试。

#define定义的标识符和宏

        #define定义的标识符和宏一般全大写。

        程序是通过预处理、编译、汇编、链接,最后才成为可执行程序.exe。

#include <stdio.h>
#define N 10//常量
#define ADD(x, y) ((x)+(y))//宏
int main()
{
	int arr[N];
	int a = 4;
	int b = 5;
	int c = ADD(a, b);
	printf("%d", c);//9
	return 0; 
}

        宏名后面加()括号,宏名和()中不能有空格,里面的参数用,隔开, 传参的时候,参数会先完成替换,再替换宏。

         #define定义的常量和宏、包含头文件在预处理阶段完成替换。

//.....stdio.h头文件展开
int main()
{
	int arr[10];
	int a = 4;
	int b = 5;
	int c = ((a)+(b));
	printf("%d", c);//9
	return 0; 
}

        宏的功能和函数非常像,宏名、函数名,都可以传参,但是宏的参数没有类型,宏业没有返回值,宏不能像函数一样实现递归(自己调用自己)。

写宏的细节

        对每一个参数都要加(),因为传的参可能是一个表达式,可能会受到操作符优先级的影响。

#define MUL(x,y) (x*y)//实现两个数相乘
int a = MUL(2+3, 4+1);

         宏是完成替换的,如果x和y不加上(),程序变为(2+3*4+1),得到的结果是15。和我们预想的不一样,不是两个数相乘。而函数不会出现这种问题,函数先计算值,函数传的是一个确定的值。

        对最后的结果要加(),可能会受到操作符优先级的影响。

#define ADD(x,y) (x)+(y)//实现两数相加
int c = 2 * ADD(4, 5);

         如果最后结果不加上,程序变为2*(4)+(5),得到的结果是13。和我们预期的不一样,不是两个数相加的和再乘2的结果。

        最后面不要加;,在很多情况下都会出问题。

#define FLAG 1;
if (FLAG) {    }

        程序编译错误,因为条件判断中多了一个;。

        宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。

        当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

#define N 10;
pritnf("N is %d", 10);

        字符串中的N不会识别成标识符,不会替换。

#和##

        define定义的宏,想将参数变成字符串,前面加上#。

#include <stdio.h>
#define STR(n) #n

int main()
{
	const char* p = STR(1+3);
	printf("%s", p);
	return 0;
}

        将1+3变成字符串,p存储字符串首元素的地址,打印字符串,输出1+3。 

         define定义的宏,想将参数名相连一起,两个参数中间加##。

#include <stdio.h>
#define FUSE(n, m) n##m

int main()
{
	int ab = 10;
	printf("%d", FUSE(a, b));
	
	return 0;
}

        a和b两个参数名合成一起变成ab,打印ab的值10.

宏的副作用

        如果宏参数是++或者--的参数,会有副作用,对参数完成替换,都是++或--的参数。

        三目运算符,条件成立执行前面的,条件不成立执行后面的。 ++和--多次修改参数。

宏参数没有类型检查

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

        可以求任意相同类型的较大值。

宏和函数

执行速度

        宏通常应用于简单的运算代码。调用函数需要准备,压参数,开辟栈帧,计算代码,最后保存并返回返回值,而宏只需要计算代码。所以宏的速度比函数快。

操作符优先级

        宏参数和结果不加括号,可能会出现操作符优先级的问题;函数的参数是计算完值再传参。

副作用参数

        宏参数完成替换,对于++和--的参数,会多次影响参数;函数的参数是计算完值再传参。

参数类型

        宏没有参数类型的检查,函数有类型的检查。

调试

        宏不能调试,函数可以调试。

递归

        宏不能递归,函数可以递归。

        宏没有类型的要求。函数的参数是特定类型的。

宏的缺点

        每次使用宏,一份宏定义的代码会插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。

        宏不能调试的。

        宏没有类型,不够严谨。

        宏可能会带来运算符优先级的问题,导致程容易出现错。

#undef

        移除一个宏定义。

条件编译

#if 常量表达式

        代码块

#endif 

        非零条件成立。,执行。

        为0条件不成立,不执行。

多分支

#if 常量表达式

        代码块

#elif 常量表达式

        代码块

#else

        代码块

#endif 

是否已经定义

        如果定义了执行。两个效果都一样。

#if defined(标识符)
    代码块
#endif

#ifdef 标识符

        代码块

#endif

        如果没定义执行。两个效果都一样。

#if !defined(标识符)

        代码块

#endif

#ifndef 标识符

        代码块

#endif

 

头文件的包含

#include <        >

#include "        "

        <>的方式直接标准路径下的头文件查询头文件。

        ""的方式先再源文件所在的目录查找头文件,如果没有,再去标准路径下的头文件查找。

        库的头文件不要使用""查找,查找效率慢一些。

避免头文件多次包含

#ifndef 标识符

#define 标识符

        头文件内容

#endif

#pragma once

        头文件内容

        这两个都可以避免一个源文件多次包含同一个头文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值