首页 > 其他分享 >预处理指令详解(C语言

预处理指令详解(C语言

时间:2023-02-09 23:22:30浏览次数:54  
标签:头文件 定义 int C语言 详解 printf return 预处理 define

一、预处理符号

预处理符号是C语言内置的符号,是可以直接使用的。

在这里插入图片描述

其中,若遵顼ANSI C,则__STDC__ 为1,否则未定义。

二、#define

1)定义标识符

define可以用来定义标识符,其语法为:#define name stuff,经过预处理后,stuff会被直接替换为name

stuff的内若过长,可在句末加上\续行符号,像这样:

#include<stdio.h>
#define Piccaso "Pablo,Diego,José\
Francisco,de,Paula,Juan,Nepomuceno\
,María,de,los,Remedios,Cipriano,de\
,la,Santísima,Trinidad,Ruiz,y,Picasso"
int main()
{
	printf("%s", Piccaso);
	return 0;
}

在这里插入图片描述

示例1: 数值替换

在这里插入图片描述

int main()
{
	int a = 100;
	return 0;
}

示例2: 循环替换

在这里插入图片描述

#include<stdio.h>
int main()
{
	while(1)
	{
		printf("A");
	}
	return 0;
}

运行代码,将会在屏幕上死循环地打印A

示例3: 分支替换

在这里插入图片描述

int main()
{
	int input = 0;
	switch (input)
	{
	case 1:
		break; 
	case 2:
		break; 
	case 3:
	}
	return 0;
}

2)宏定义

define允许有参数的文本替换,这种操作通常称为宏,其语法为:#define name(list) stuff,其中,list是由逗号隔开的符号表,符号有可能出现在stuff中。

示例1:

在这里插入图片描述

int main()
{
	printf("%d", 5+5);
	return 0;
}

示例2:

在这里插入图片描述

int main()
{
	printf("%d", 10*double(5+1));
	return 0;
}

因为#define的功能只是替换,若要利用宏定义实现快捷的函数操作,最好的方法是在宏定义时多加括号,以便于达到整体求值的效果,像这样:#define double(x) (x)+(x)

注意: 由于宏是直接替换,因此传参时严禁使用自增,自减,传参时使用,替换后依然会再次执行,会导致不可预测的后果。

3)字符串转换符#

字符串有自动连接的特点,例如运行以下这段代码:

#include<stdio.h>
int main()
{
	printf("123" "456");
	return 0;
}

效果图:

在这里插入图片描述

字符串转换符#就是利用这个特性,它可以将宏定义中传入的参数,替换为字符串格式。

#include<stdio.h>
#define sum(x) printf("the val of "#x" is %d",x)
int main()
{
	int a = 10;
	sum(a);
	return 0;
}

在上述代码中,#号a直接转化为字符串,随后三个字符串拼接在一起。

效果图:

在这里插入图片描述
利用该方法可以只传参一次实现值和名同时打印。

4)片段链接符##

在宏定义时,片段连接符##可以实现将两个符号连接在一起,使其成为一个符号,前提是这个合成的符号必须已经被定义。

#include<stdio.h>
#define double(x) sum##x*=2
int main()
{
	int sum1 = 1;
	int sum2 = 1;
	int sum3 = 1;
	double(1);
	printf("%d %d %d", sum1, sum2, sum3);
	return 0;
}

在上述代码中,##会把sum和参数x连接在一起,当我们传入1经过预处理后,等效于:sum1*=2

效果图:

在这里插入图片描述

5)宏定义VS函数

宏定义的优势:

  • 宏定义的执行速度远远超过函数,当执行简单的计算时,更适合使用宏定义。
  • 宏定义传参时没有类型检测,可以将任意的数据传入。
  • 宏定义是直接替换,可以传入各种各样的符号,实现许许多多函数做不到的功能。(可以传入类型、传入函数、传入语句等等

宏定义的劣势:

  1. 宏定义不能调试、不能递归,因此宏定义只适合做简单的计算。
  2. 宏定义是直接替换,因此相邻操作符的优先级很有可能产生不期望的顺序,因此要尽可能带括号。
  3. 宏定义传参没有类型检测,因此不够严谨。

6)命名公约

以下几条公约,必须遵守

  1. 宏定义的名必须全部大写。
  2. 函数名不可以全部大写。

三、#undef

#undef宏定义删除,可以在函数内部使用!

在这里插入图片描述

被删除后的标识就不能再使用了。

四、命令行编译

指在VScodeLinux等用命令行执行编译的环境下,可以在编译时对变量进行赋值。

五、条件编译

在写程序时,有些代码是为了查看某个部分是否正确而写的的调试代码。

删除很可惜,但又不想让其编译,此时就可以使用选择性编译

但实质上使用if语句或直接注释会更加方便,但在C语言内置的头文件中,为了节约时间经常使用条件编译。

1)常量表达式判断

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

常量表达式为真,则中间的语句编译;
常量表达式为假,则中间的语句不编译。

此外,也可以写成多分支的表达式条件编译。

int main()
{
#if 0
	printf("111");
#elif 1
	printf("222");
#else 0
	printf("333");
#endif
	return 0;
}

效果图:

在这里插入图片描述

2)是否定义判断

判断某个符号是否被定义,只要被定义,就编译中间的语句,无论其被定义为什么。

#include<stdio.h>
#define MAX
int main()
{
#if defined(MAX)//或#ifdef MAX
	printf("111");
#endif

	return 0;
}

或判断某个符号是否没定义,没定义则编译。

#include<stdio.h>
#define MAX
int main()
{
#if !defined(MAX)//或#ifndef MAX
	printf("111");
#endif

	return 0;
}

3)嵌套判断

条件编译是可以互相嵌套的。

#include<stdio.h>
#define DEBUG 
int main()
{
	#ifdef DEBUG
#if 1
	printf("111");
#elif 0
	printf("222");
#endif
#endif 

	return 0;
}

如上述代码是在是否定义判断中嵌套常量表达式判断。

效果图:

在这里插入图片描述

六、头文件的包含

1)双引号与尖括号

对于#include来说,后面的文件有两种引用方法:

  1. 双引号,优先在本地文件寻找,找不到再去标准库中寻找,都没有则报错。
  2. 尖括号,直接在标准库中寻找,找不到则报错。

所有的头文件在包含时都可以使用双引号,但为了速度和区别位置,建议自己写的头文件用双引号,标准库中的用尖括号

2)头文件的嵌套包含

可以将许许多多的头文件都包含在一个自己创建的头文件中,最后只需要在其他的源文件中包含该自己创建的头文件即可,像这样:

在这里插入图片描述

3)头文件重复包含解决方法

在写多人合作的大型项目时,每个程序员可能都要包含一次公用的头文件,当他们写的代码汇总时,这个头文件可能会被包含多次。

因此,我们使用条件编译来解决这个问题。

#if !defined(TIME)
#define TIME 
//...
//...   //在这里实现各种函数
//...
#endif

假设上述代码为head.h,当我们第一次包含head.h时,由于TIME没有被定义,因此会定义一个TIME,同时编译里面的函数。

当我们第二次包含head.h时,因为TIME被定义过了,即使head.h里面的内容被拷贝到源文件中,也不会进行编译,从而加快了速度。

注意: 在头文件开头加入#pragma once即可一键实现上述效果,不必冗杂的代码,但仅限于自己写的头文件,标准库的头文件已经帮你加完了。


感谢您的阅读与耐心~

标签:头文件,定义,int,C语言,详解,printf,return,预处理,define
From: https://www.cnblogs.com/infei/p/17107466.html

相关文章

  • C语言--void
    C语言中存在空类型(void),这种类型表示“空”void时基础类型,不是基础数据类型,不能定义变量void可用于函数参数,表示函数无参数void可用于函数返回类型,表示函数无返回值C语......
  • C语言--函数参数深度剖析
    函数定义时参数没有具体值,函数调用时指定参数初始值函数参数在函数内部等同于普通变量在C语言中,数组作为函数参数传递时,大小信息丢失在函数内部修改数组形参,将影响数组......
  • C语言--深入浅出函数调用
    1.main()是应用程序与操作系统的一个“约定”;当操作系统运行应用程序时,首先调用的就是main()函数;应用程序必须运行于操作系统,接受操作系统管理2.应用程序的运行3.深......
  • C语言--初识函数
     ......
  • C语言学习1
    常见的校招/社招要求:1.计算机语言(C/C++/JAVA等);2.数据结构和算法3.操作系统;4.计算机网络+网络编程;5.数据库;6.脚本语言。计算机语言的学习不要贪多而不精,选一门深入学......
  • C语言填空:阶乘
    #include<stdio.h>//求任意整数的阶乘//如果输入3则输出3!=6main(){intn,a,c=1;scanf("%d",&n);for(a=1;【1】;a++)c=【2】;printf("%d!......
  • zookeeper详解
    ————————————————什么时候新建日志文件:1、在进行事务日志写入之前,zookeeper会判断是否正在关联一个可写的事务日志文件,如果有则继续追加,如果没有就新......
  • kafka配置详解
    关闭自动消费Spring-Boot-kafka的配置中有一个参数,提供了自动消费的功能。使用自动消费我们在收到消息的时候会自动向kafka确认消费。但是在一些特殊场景中我们可能需要使......
  • c语言填空:两个数组计算
    #include<stdio.h>//求出a中各相邻两个元素的和,并将这些和存放在数组b中//按每行3个元素的形式输出。例如:b[1]=a[1]+a[0],....,b[9]=a[9]+a[8]main(){inta[10......
  • js构造函数详解
    1.构造函数介绍构造函数是专门用来生成对象的函数,它提供模板,描述对象的基本结构。一个构造函数,可以生成多个对象,这些对象都有相同的结构。构造函数的写法就是一个普通的函......