当前位置: 首页 > article >正文

【C语言从不挂科到高绩点】17-C语言中的宏定义

Hello!彦祖们,俺又回来了!!!,继续给大家分享 《C语言从不挂科到高绩点》课程!! 本节将为大家讲解C语言中的函数:

本套课程将会从0基础讲解C语言核心技术,适合人群:

  1. 大学中开设了C语言课程的同学
  2. 想要专升本或者考研的同学
  3. 想要考计算机等级证书的同学
  4. 想要从事C/C++/嵌入式开发的同学

================点个关注吧================

=========================================

八、C语言中的宏定义

8.1 宏定义概述

#define 宏定义命令,是 C 语言的预处理命令。所谓的预处理命令在代码编译之前需要做的处理。

所谓的宏定义,就是用一个标识符来表示一个字符串,如果在后面代码中出现了该标识符,那么就会全部替换成指定的字符串

#include <stdio.h>

// 定义了一个宏,名字叫N,对应的字符串内容是100
// 表示在后续的代码中,但凡用到N就会被直接替换成100
#define N 100

int main(){
	// N是宏,在编译代码之前,会先将N替换成100
	// 在编译代码的时候,下面的代码已经变成了 int sum = 100+100;
	int sum = N+N;

	int result = N*N;

	printf("sum=%d,result=%d\n", sum,result);
	return 0;
}

上面案例中,在编译代码之前,代码中所有的 N 都会被替换成 100

宏定义的一般格式为:

#define 宏名 字符串

8.2 宏定义的使用场景

当程序中有反复需要使用的且比较复杂的表达式的时候,可以将这个表达式定义成宏。

#define M (n*n+3*n)

它的作用,就是用指定的标识符 M 来表示(n*n+3*n),在编写代码的时候需要用到(n*n+3*n)的时候,就可以用 M 来代替

#include <stdio.h>

#define M (n*n+3*n)

#define K n*n+3*n

int main(){

	int n = 0;
	printf("请输入一个整数:");
	scanf("%d",&n);


	int sum = 3*M+4*M+5*M; // 每一个M都会被替换成(n*n+3*n)
	// 经过预处理之后 int sum = 3*(n*n+3*n)+4*(n*n+3*n)+5*(n*n+3*n)
	printf("sum=%d\n", sum);

	int result = 3*K+4*K+5*K;
	printf("result=%d\n", result);
	// 经过预处理之后 int sum = 3*n*n+3*n+4*n*n+3*n+5*n*n+3*n


	return 0;
}

需要注意的问题:当做宏替换(宏展开)的时候,是将宏名原封不动的替换成字符串。不会添加任何符号也不会删除任何符号

8.3 宏注意事项

  1. 宏定义时,宏名表示一个字符串,宏定义不是语句,在行末不需要加分号,如果加上分号,就会连同分号一起替换。
  2. 宏定义必须写在函数外,它的作用域为从宏定义命令开始到源程序结束。如果要提前终止宏,可以使用#undef 命令
#include <stdio.h>

// 宏定义默认情况下作用范围从定义开始,到程序结束
#define PI 3.1415926   // 安装PI


void func();

int main(){
	printf("main:半径为3的圆的面积为:%lf\n",PI*3*3 );

	func();

	return 0;
}

// 如果要禁用宏,可以使用#undef
#undef PI    // 卸载PI

void func(){
	printf("func:半径为3的圆的面积为:%lf\n",PI*3*3 );
}

终止禁用宏之后,如果再使用宏,就会出现如下的错误:

  1. 宏定义允许嵌套,在定义宏的字符串中可以使用已经定义好的宏名。宏替换(宏展开)的时候会层层替换。
#include <stdio.h>

// 宏定义默认情况下作用范围从定义开始,到程序结束
#define PI 3.1415926   // 安装PI

#define S PI*r*r   // 在名字为S的宏中,使用了名字为PI的宏


void func();

int main(){
	printf("main:半径为3的圆的面积为:%lf\n",PI*3*3 );

	int r = 3;

	// 第1步:宏展开:S被替换成:PI*r*r
	// 第2步:宏展开:PI被替换成3.1415926 :3.1415926*r*r
	// 最终输出语句中S会被替换成:3.1415926*r*r
	printf("【main】:半径为3的圆的面积为:%lf\n",S);

	func();

	return 0;
}

// 如果要禁用宏,可以使用#undef
//#undef PI    // 卸载PI

void func(){
	printf("func:半径为3的圆的面积为:%lf\n",PI*3*3 );
}

需要注意的问题:如果宏替换的字符串中,存在变量名。那么在使用宏之前,一定要先定义这些变量。上面代码中 S 的宏中 PI*r*r 中包含了变量 r,在使用 S 之前一定要先定义 r。

所以:一般建议宏名全大写,目的在于可以区分那些是宏名哪些是变量名

  1. 可以用宏定义表示数据类型
#include <stdio.h>

#define UINT unsigned int

int main(){


	UINT a=10; // 宏替换之后: unsigned int a = 10;

	UINT c,b=20;


	printf("a=%d,b=%d,c=%d \n",a,b,c );

}

总体来说,宏展开只是做的简单字符串替换,由预处理器在编译代码之前进行处理的

8.4 带参数的宏

C 语言中允许带参数的宏,在宏定义中的参数,称为形式参数,在宏调用中的参数称为实际参数。

带参数的宏定义的一般格式为:

#define 宏名(参数列表)  字符串

带参数的宏调用的一般形式为

宏名(实参列表)

比如:

#define M(y)  y*y+y*3

k = M(5); // 宏调用

在预处理阶段(编译之前),用实际参数 5 去代替形式参数 y,经过预处理之后的语句

k =  5*5 + 5*3

【案例代码】

#include <stdio.h>

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


int main(){

	int x,y ,max;

	printf("请输入两个数:");
	scanf("%d %d",&x,&y);

	max = MAX(x,y);  // 宏替换之后:x>y?x:y

	printf("最大值为:%d\n",max );
	return 0;
}

需要注意的问题:带参数的宏和函数区别

  1. 宏展开仅仅是字符串的替换,不会对表达式进行计算。
  2. 宏在编译之前就已经被处理掉了(做好了字符串替换了),宏没有机会参与编译,宏不会占用内存
  3. 函数是一段可以重复使用的代码,会被编译,会给它分配内存,每次调用函数,就是执行这块内存中的代码。

【练习】定义一个宏,来计算指定天数一共有多少秒

【参考代码】

#include <stdio.h>


// 普通的宏替换
// #define SEC day*24*60*60

// 带参数的宏
// #define SEC(n) n*24*60*60


// 宏嵌套
#define SEC 24*60*60

#define TIM day*SEC


int main(){

	printf("请输入一个天数:");
	int day = 0;
	scanf("%d",&day);

	// printf("%d天一共有%d秒\n",day, SEC);
	// printf("%d天一共有%d秒\n",day, SEC(day)); // day*24*60*60
	printf("%d天一共有%d秒\n",day, TIM);
	return 0;
}

8.5 #和##用法

#用来将宏参数转换成字符串,也就是在宏参数的开头和末尾加上引号,比如:

#define STR(s)  #s

会将参数 s 变成字符串,s 会用双引号包裹起来。

#include <stdio.h>

#define STR(s)  #s


int main(){

	printf("%s\n", STR(哈哈) );


	printf("%s\n", STR("哈哈") );
	return 0;
}

运行效果:

##称为连接符,用来将宏参数或者其他字符串串联起来,比如:

#define CON1(a,b)  a##e##b
#define CON2(a,b)  a##b##00

【参考代码】

#include <stdio.h>


#define CON1(a,b)  a##e##b
#define CON2(a,b)  a##b##00


int main(){
	printf("%f\n",CON1(8.5,2) );  // 8.5e2
	printf("%d\n",CON2(8,5) ); //8500
	return 0;
}

运行效果:

 ---------------------------------------------------------------------- 

分享不易,耗时耗力,喜欢的同学给个关注和赞吧

承接毕设指导,技术答疑,学习路上想要找私人教练的同学可以私信我

更多学习资料,公众号:墨轩学习网,B站:墨轩大楼

----------------------------------------------------------------------

另有下图需求的也记得私信我哟,专业班子


 


http://www.kler.cn/a/302039.html

相关文章:

  • 二分搜索的三种方法
  • HARCT 2025 分论坛4:智能系统传感、传感器开发和数据融合中的智能数据分析
  • 计算机网络HTTP——针对实习面试
  • Elasticsearch retrievers 通常与 Elasticsearch 8.16.0 一起正式发布!
  • 卡尔曼滤波:从理论到应用的简介
  • 【CICD】CICD 持续集成与持续交付在测试中的应用
  • 云服务器 卸载mysql5并安装mysql8(图文)
  • docker-compose 部署 flink
  • 笔试强训day10
  • C#基础(10)变长参数和参数默认值
  • 数据结构之数组矩阵存储
  • 树莓派安装 OpenCV 教程
  • 110个oracle常用函数总结
  • uniapp中基于vue3实现输入验证码功能
  • Android 地图搜索商家,检索关键字(高德地图,百度地图),地址搜索(1)
  • windows 显示进程地址空间
  • win11下面的virtualenv的使用(没写完)
  • Excel文档的读取(3)
  • 93、k8s之hpa+helm
  • AI prompt(提示词)
  • 根据ArrayList<Object>中对象的多个属性值进行模糊匹配,并找到所有匹配的对象
  • 企业应该如何安全上网,软件防查盗版,企业防盗版
  • uniapp如何监听页面滚动?
  • Boost.pyhon 使用方法
  • 图片详解,最简单易懂!!!Ubuntu增强功能
  • 轮询解决方案