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

news2024/9/20 0:47:05

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.coloradmin.cn/o/2130979.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

取消Cursor的注释斜体字风格

1. 打开settings.json 2. 添加如下代码 "editor.tokenColorCustomizations": {"textMateRules": [{"name": "Comment","scope": ["comment","comment.block","comment.block.documentation"…

Vert.x HttpClient调用后端服务时使用Idle Timeout和KeepAlive Timeout的行为分析

其实网上有大量讨论HTTP长连接的文章&#xff0c;而且Idle Timeout和KeepAlive Timeout都是HTTP协议上的事情&#xff0c;跟Vert.x本身没有太大关系&#xff0c;只不过最近在项目上遇到了一些问题&#xff0c;用到了Vert.x的HttpClient&#xff0c;就干脆总结一下&#xff0c;留…

从Apple Intelligence到IoT Intelligence,端侧生成式AI时代加速到来

9月10日凌晨1点&#xff0c;苹果新品发布会如期举行&#xff0c;全新iPhone16系列成为苹果生态中真正意义上的第一款原生AI手机&#xff0c;在第二代3nm工艺A18和A18 Pro芯片的加持下&#xff0c;iPhone16系列能够容纳并快速运行以Apple Intelligence为中心的生成式AI功能在手机…

铭顺元宇宙时代到来,数字人应用案例分享

近年来&#xff0c;随着技术的不断发展&#xff0c;数字人的功能和表现力也在不断提升&#xff0c;形形色色的虚拟数字人正代替真人&#xff0c;扮演着代言人、主播、客服和智能助理的角色&#xff0c;涉及文旅、电商、金融等多个行业。作为随着AI技术在数字人产业中的发展&…

远程桌面内网穿透是什么?有什么作用?

远程桌面内网穿透指的是通过特定技术手段&#xff0c;将处于内网中的电脑或服务器&#xff0c;通过外部网络&#xff08;互联网&#xff09;进行访问。内网穿透的主要作用是解决在内网环境下&#xff0c;远程设备与外部互联网之间的连接问题&#xff0c;允许用户从外部访问内网…

硬核,这款小而美的国产操作系统开源了!(带私活源码)

今天给大家介绍的是硬核的国产物联网操作系统 RT-Thread&#xff0c;内容很硬核&#xff0c;可以让大家捡起一些大学期间学到的知识&#xff0c;也能让自己对于操作系统有更多的理解。 项目介绍 RT-Thread 诞生于 2006 年&#xff0c;是一款以开源的物联网操作系统。主要采用…

07 vue3之组件及生命周期

组件基础 每一个.vue 文件呢都可以充当组件来使用 每一个组件都可以复用 组件的生命周期 简单来说就是一个组件从创建 到 销毁的 过程 成为生命周期 在我们使用Vue3 组合式API 是没有 beforeCreate 和 created 这两个生命周期的 onBeforeMount() 在组件DOM实际渲染安装之前…

一个未解决的漏洞:actuator字符绕过漏洞

最近遇到了安全部门派发的actuator泄漏漏洞&#xff0c;领导希望不暴露到外网上&#xff0c;对于内网需要认证才可以访问。 要想不暴露到外网上&#xff0c;就需要在网络层面做拦截&#xff0c;比如nginx和apisix上做代理配置。 一般的情况都可以应对&#xff0c;就是对于http…

CentOS镜像源更新

如果 CentOS 7.9 的官方镜像源已不维护&#xff0c;你可以使用以下方法更新&#xff1a; 切换到其他镜像源&#xff1a;使用 CentOS 镜像站点或第三方镜像源&#xff0c;如 EPEL&#xff08;Extra Packages for Enterprise Linux&#xff09;。修改 /etc/yum.repos.d/CentOS-Ba…

Web大学生网页作业成品——动漫火影忍者网页设计与实现(HTML+CSS+JS)(5个页面)

&#x1f389;&#x1f389;&#x1f389; 常见网页设计作业题材有**汽车、环保、明星、文化、国家、抗疫、景点、人物、体育、植物、公益、图书、节日、游戏、商城、旅游、家乡、学校、电影、动漫、非遗、动物、个人、企业、美食、婚纱、其他**等网页设计题目, 可满足大学生网…

终于有一本书把大模型背后的Transformer模型究竟是什么一次性说清楚了!

前言 ChatGPT红得发紫&#xff0c;强得让人类心悸。但在它的背后&#xff0c;还隐藏着一位真正的大佬。它的名字叫做——Transformer! 这本书全面介绍了最新的Transformer模型在自然语言处理中的应用方法和技巧&#xff0c;包括原理、实现方法和各种任务的应用&#xff0c;提供…

WebSocket和HTTP协议有什么区别

WebSocket 支持端对端通信可由client发起&#xff0c;也可由sever发起用于消息通知、直播间讨论区、聊天室、协同编辑 WebSocket连接过程 先发起一个HTTP请求成功之后在升级到WebSocket协议&#xff0c;再通讯 WebSocket和HTTP区别 WebSocket协议名是ws://&#xff0c;可双…

C语言存储类型 auto,register,static,extern

目录 1. auto 存储类型 1.1 自动变量特性 1.2 举例 2. register 存储类型 2.1 寄存器变量特性 2.2 举例 3. extern 存储类型 3.1 extern 存储类型特性 3.2 举例 3.2.1 extern全局变量 ​编辑 3.2.2 extern函数 4. static 存储类型 4.1 static 存储类型特性 4.2 举…

克雷格·费德里吉谈Apple Intelligence保密技术背后的挑战

苹果必须实现克雷格-费德里吉所说的突破&#xff0c;这样 Apple Intelligence公司才能在云中使用大型语言模型&#xff0c;同时还能保护用户隐私&#xff0c;苹果是这样做的。在"It’s Glowtime"活动中&#xff0c;苹果公司谈到了私有云计算作为保护用户隐私的方式。…

Java发邮件:如何配置SMTP服务器实现发信?

Java发邮件功能实现的教程&#xff1f;Java发邮件的方式有哪些&#xff1f; 无论是用于用户注册确认、密码重置&#xff0c;还是系统通知&#xff0c;Java发邮件都是不可或缺的一部分。AokSend将详细介绍如何配置SMTP服务器&#xff0c;以便在Java发邮件时能够顺利发送邮件。 …

【Kubernetes】linux centos安装部署Kubernetes集群

【Kubernetes】centos安装Kubernetes集群 1、环境准备 系统centos7 配置yum源参考文章 Centos系统换yum源 步骤1-3是所有主机都要配置&#xff0c;主机名和hosts配置完后可以使用工具命令同步 1.1 主机 一主二从 主机名ipk8smaster192.168.59.148k8snode1192.168.59.149…

App结合3D形象的技术实现选择

在为App添加3D人物交互效果时&#xff0c;可以采用多种技术&#xff0c;具体选择取决于你的目标平台&#xff08;iOS、Android、跨平台&#xff09;以及项目的复杂性和需求。 以下是几种常用技术及其特点&#xff1a; 游戏引擎技术 游戏引擎提供了强大的3D图形渲染和交互功能&…

05 输出三角形面积和周长

题目&#xff1a; 代码&#xff1a; #include<iostream> using namespace std;#include<stdio.h> #include<stdlib.h>#include<math.h>int main() {int a,b,c;cin>>a>>b>>c;if(ab>c&&ac>b&&bc>a){;}else{…

打包yolov8目标检测模型为exe的教程(pyinstaller 打包pyQt5 界面为exe)

要将YOLOv8模型的应用程序打包成EXE可执行文件&#xff0c;您可以遵循以下步骤&#xff0c;这里使用的是PyInstaller作为打包工具。请注意&#xff0c;这个过程可能会因为您的环境和依赖关系的不同而有所变化。以下是一个基本的指南&#xff1a; 步骤 1: 安装必要的库 确保您…

RabbitMQ 07 另两种集群方式 warren(主备模式),shovel(远程模式)

01.之前的集群有一个缺点&#xff0c;就是故障恢复的时候&#xff0c;停留在队列中的消息怎么办&#xff1f; 02.镜像集群模式&#xff0c;同步所有消息&#xff0c;当当前主节点不可用的时候&#xff0c;可以选举一个从节点来作为主节点。这样可以避免因为主节点不可用的情况…