预处理

一、#define

#define实现的就是文本的代替表示,即#define x y ->用文本x代替表示y的内容,y的内容什么都可以,可以是常量、变量、表达式或者几段代码等等都可以

 

1.#define 定义常量

#define M 100
int main()
{
    printf("%d\n",M);
    return 0;
}

 文本M代替表示的是常量值100,所以打印的值是100


2.#define 定义宏

当用文本代替表示的内容含有参数时,#define就形成了宏

  •  #define  name(paramen-tlist)  stuff
  • #define      名称(参数,参数)     含参内容

左边这一块是文本,右边这一块是文本表示的内容

由于含有参数,代替时是左边含参的文本代替表示右边含参的内容,但其本质还是不变的,就是文本对内容的替换,只不过里面含有了参,替换时,要根据参数将参数代上去替换,得到此参数下的文本和此参数下其对应的代替内容,然后就可以知道此参数下的文本代替的值是什么了

宏的特点:

其实说是参数,其实宏的参数是什么都能传,因为宏的传参本质上也是文本式替换操作,对传的内容都视为文本式的,对表达式文本不会算好再替换(因为视为纯文本),而是文本纯替换好后才开始对内容进行计算,所以根据它的特点,要注意一下几点:

2.1.参数传过去替换的过程中,是不加以任何计算的,参数原原本本传过去传完后才开始计算

定义一个宏,用来求平方
#define SQUARE(n)  n*n
将含参表达式n*n这个内容替换为了SQUARE(n) 这个有参数结合的文本
int main()
{
    int ret1,ret2 = 0;


	ret1 = SQUARE(6);
	printf("%d\n", ret1);//36

    ret2 = SQUARE(5+1);
	printf("%d\n", ret2);//11


	return 0;
}

因为宏传过去的过程中是不加任何计算的,全部过去后才开始计算的,所以还原SQUARE(5+1)此文本代替的内容为5+1*5+1= 11,所以定义时(n)*(n)每一个参数都要加上括号,(5+1)*(5+1) = 36,这样就没问题了

还有一个例子:

定义一个宏,用来求一个数的2倍
#define DOUBLE(x) ((x)+(x))
int main()
{
	int ret = 0;
	ret = 10 * DOUBLE(5);
	printf("%d\n", ret);//100
    10*((5)+(5)) = 100

	如果(x)+(x)外层不加括号:
	-> 10*(5)+(5) = 55

	return 0;
}

所以,内每一个x都要有括号括,外x构成的整体外部也要有括号括,总之,写宏时不要吝啬括号


2.2.宏的参数在宏体如果是出现多次的话,那么当传过来的参数是带有副作用的表达式时,参数都换成副作用表达式,副作用就不是预想的只产生一次的了,而是会产生多次

写一个宏,求2个数的较大值

#define MAX(X,Y) ((X)>(Y)?(X):(Y))

int main()
{
	int a = 3;
	int b = 5;
	int m = MAX(a++, b++);

    宏传参传过去里面全替换后:				   
	-> int m = ((a++)>(b++)?(a++):(b++));
                                 选择语句,选择执行(b++)
    1.后置++下,表达式算完再++ ——> a = 3 < b = 5 ,表达式比较完后a++后为4;b++后为6,选择执行(b++)语句
    2.执行(b++)语句,b++为后置++,先把值赋给m, m = b = 6 ,然后b++为7


	printf("m = %d\n", m);//6
	printf("a = %d\n", a);//4
	printf("b = %d\n", b);//7

	return 0;
}

2.3.宏都是替换式过去,文本式替换,什么都能替换,什么都能传

宏传类型如下:

#include<stdlib.h>

#define Malloc(n,type) (type*)malloc(n*sizeof(type))

int main()
{
	int* p = (int*)malloc(10 * sizeof(int));

	               这里宏传的参是类型
	int* ptr = Malloc(10, int);
 ——>int* ptr = (int*)malloc(10*sizeof(int));
}

2.4.宏的参数去找替换时它至少要按符号单位去替换的

举个例子:比如下图中要用参数传来的int替换函数名标识符type_max中的type,因为type与_max构成了标识符符号单位,int来替换时是做不到替换标识符部分的,因为它替换时的最小单位是符号,要换就要type_max这个标识符,而不能换里面的type标识符的一部分

所以,我们可以用 ## 操作符,它可以实现把符号切割,创建更小的合法的符号单位,即type##_max中,参数int来替换时,此时type是一个合法的符号单位,可以完成替换,即int##_max,替换好后,##又会将两端的符号单位合并,合并成一个符号单位—>int_max,此时就完成了参数在名字里部分的替换,形成了由参数部分构成的函数名,这样就可以实现声明多种不同函数类型的函数(它们函数名是不同的),实现批量制造函数了

定义一个声明函数的宏    声明函数的模具
#define GENERIC_MAX(type)             \
       type type##_max(type x, type y)\
      {                               \
          return x>y?x:y;             \
      }

用宏替换完后是一个函数的声明  利用宏实现可以一句代码批量声明函数
GENERIC_MAX(int); 
  int int_max(int x, int y){   return x>y?x:y;}
  ——>即:
    // int int_max(int x, int y)
    //{
    //    return x > y ? x : y;\
    //}

int main()
{
	int r = int_max(3, 5);

	printf("%d\n", r);//5

    return 0;
}

二、条件编译

1)#if... #elif ... #else ... #endif

2)#if defined() ... #endif  <=> #ifdef ...  #endif 

3)#if !defined() ... #endif <=>#ifndef ... #endif 

 

判断是否被定义:

#define MAX 1
int main()
{
#ifdef用来判断符号是否被程序员定义过:

如果MAX被定义过为真
    #ifdef MAX
    printf("MAX已定义\n");

如果MAX未被定义
    #else
    printf("MAX未定义\n");
    #endif
    return 0;
}

1.每一个#if(包括#ifdef 、#ifndef)都要有 #endif 匹配的,都要有一一对应 (elif不属于#if)

2.#if到对应#endif的整块区域为一个条件编译判断区,不用{}括因为#endif会自动找#if匹配

3.#这些条件预处理的指令判断为假的部分,在源文件预处理中不会执行,在预处理后的预编译代码.i中也已经是直接删掉了那种,不会出现在后面的工程文件里,它最多只是在源文件中露了面的那种(跳过没去执行)


(补充:#undef 用于移除一个宏定义:)

#define MAX 100
int main()
{
    printf("%d\n",MAX);100
    #undef MAX
    printf("%d\n",MAX);MAX未定义
}

三、头文件的包含

#include"add.h"与#include<add.h>:

  • #include"add.h"—>会先在源文件所在目录下查找,如果文件未找到,就会去标准库里查找

  • #include<add.h>—>直接去标准库里查找

为避免嵌套文件时头文件的重复包含引入,在每个头文件的开头写:

  • #ifndef __TEST_H__
    #define __TSET_H__
    
    头文件的内容
    
    #endif
    

或:

  • #pragma once
    头文件内容

 

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值