预处理(详解)

预定义符号

—FILE — //进行编译的源文件
—LINE — //文件当前的行号
—DATE — //文件被编译的日期
—TIME — //文件被编译的时间
—STDC — //如果编译器遵循ANSI C,其值为1,否则未定义

printf("file:%s line:%d\n", __FILE__, __LINE__);

#define

#define 定义标识符

#define MAX 1000 #define reg register
//为 register这个关键字,创建一个简短的名字

#define do_forever for(; ;)
//用更形象的符号来替换一种实现

#define CASE break;case
//在写case语句的时候自动把 break写上。

// 如果定义的 stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠==(续行符)==。

  #define DEBUG_PRINT printf("file:%s\tline:%d\t \
                                              date:%s\ttime:%s\n" ,\
                                                —FILE —, —LINE — , \ 
                                                —DATE —, —TIME — )

#define 定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)

#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意:
参数列表的左括号必须与name紧邻
否则就会被误认为是定义标识符

#include<stdio.h>
#define SQUARE(X) ((X)*(X))
int main()
{
	int r = SQUARE(5);
	printf("%d", r);
	return 0;
}

在这里插入图片描述
注意:1.宏参数和#define 定义中而可以出现其他的 #define 定义的符号
但是对于宏,不能出现递归
2.当预处理器搜素#define 定义的符号时,字符串常量的内容不被搜索

#和##

在这里插入图片描述
对于printf 函数可以这样由几个字符串一起 构成一个
在这里插入图片描述

在这里插入图片描述
#N 转换它所对应的字符串
就变为 printf (“the value of “a” ”is %d\n",a); 几个字符串连一起 成一句

当然,也可以以不同类型打印
在这里插入图片描述
在这里插入图片描述

可以把位于两边的符号合成一个符号

#include<stdio.h>
#define CAT(Class,Num) Class##Num
int main()
{
	int Class106 = 100;
	printf("%d",CAT(Class, 106));  //printf("%d",Class106);
	return 0;
}

在这里插入图片描述

带副作用的宏参数

当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。

例如:
x+1; //不带副作用
x++; //带有副作用

#include<stdio.h>
#define MAX(X,Y) ((X)>(Y)?(X):(Y)) 
int main()
{
	int a = 3;
	int b = 5;
	int m = MAX(a++, b++);
	//((a++)>(b++)?(a++):(b++)) 
	//3>5?    //后来a=4,b=6
	//条件不成立  执行 b++ m=6//后来b=7 //没执行语句,就不去运算了,a=4不去加了
	printf("m=%d\n", m);//6
	printf("a=%d b=%d", a, b);//4 7
	return 0;
}

在这里插入图片描述

宏和函数做对比

//宏
#define MAX(X,Y) ((X)>(Y)?(X):(Y))
// 函数
int Max(int x, int y)
{
return (x > y ? x : y);
}

用宏来比较两个数最好
原因:
1.宏比函数在程序规模上和速度上更胜一筹
2.宏是类型无关的


MAX(2,3)可以
MAX(1.5,3.6)也可以
而函数
Max(2,3) 可以
Max(1.5,3.6)不可以,参数类型不符合

宏缺点:

  1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
  2. 宏是没法调试的。
    (在预处理的时候#define 改替换的替换了,在调试的时候虽然看着原来的代码,但是却被改得不一样了)
  3. 宏由于类型无关,也就不够严谨。
  4. 宏可能会带来运算符优先级的问题,导致程容易出现错。
    (即,该加括号就加,不要吝啬括号)

宏有时候可以做到函数做不到的事情
(宏参数可以出现类型,但是函数不可以)

#include<stdio.h>
#define MALLOC(NUM,TYPE)\
 (TYPE*)malloc((NUM)*sizeof(TYPE))
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));
	// int *p=MALLOC(10,int);
}

总:足够简单用宏,复杂易错用函数

命名约定

一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。

把宏名全部大写
函数名不要全部大写

undef

用于移除一个宏定义

#include<stdio.h>
#define MAX 100
int main()
{
	printf("%d", M);
#undef M
	printf("%d", M);
	return 0;
}

在这里插入图片描述

命令行定义

许多C 的编译器提供了一种能力,允许在命令行中定义符号。用于启动编译过程
例如,在linux 的gcc 编译器上,对编译的程序进行再次命令

条件编译

对于调试性的代码,删了可惜,留着碍事,于是可以选择性编译

#include<stdio.h>
//#define _DEBUG_
int main()
{
	int i = 0;
	int arr[10] = { 0 };
	for (i = 0;i < 10;i++)
	{
		arr[i] = i;
#ifdef _DEBUG_
		printf("%d", arr[i]);
#endif
	}
	return 0;
}

在这里插入图片描述
在这里插入图片描述
常见的条件编译指令:
1.
#if 常量表达式
//…
#endif
//常量表达式由预处理器求值。
如:

#define —DEBUG__ 1
#if —DEBUG—
 //..
#endif

也可

#if 1//条件为真执行
//...
#endif

#if 0//条件为假不执行
//...
#endif

#if 2==3//条件为假不执行
//...
#endif

2.多个分支的条件编译

#if 常量表达式
 //...
#elif  常量表达式
 //...
#else
 //...
#endif

如:

#include<stdio.h>
#define M 6
int main()
{
#if M < 5
		printf("hehe");
#elif M==5
	printf("haha");
#else
	printf("heihei");
#endif
	return 0;
}

3.判断是否被定义

#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
#include<stdio.h>
#define MAx 100
int main()
{
#if defined(MAX)
		printf("max\n");
#endif
	return  0;
}

//#define MAx 100
int main()
{
#if !defined(MAX)
	printf("max\n");
#endif
	return  0;
}

4.嵌套指令

#if defined(OS_UNIX)
 #ifdef OPTION1
 unix_version_option1();
 #endif
 #ifdef OPTION2
 unix_version_option2();
 #endif
#elif defined(OS_MSDOS)
 #ifdef OPTION2
 msdos_version_option2();
 #endif
#endif
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值