C语言——宏定义

C语言——宏定义一 预处理 编译一个 C 语言程序的第一步骤就是预处理阶段 这一阶段就是宏发挥作用的阶段 C 预处理器在源代码编译之前对其进行一些文本性质的操作 主要任务包括删除注释 插入被 include 进来的文件内容 定义和替换由 define 定义的符号以及确定代码部分内容是否根据条件编译 if 来进行编译 文本性质 的操作 就是指一段文本替换成另外一段文本 而不考虑其中任何的语义内容 宏仅仅是在 C 预处理阶段的一种文本替换工具 编译完之后对二进制代码不可见二 宏定义用法 宏常量 我们最常使用到

一.预处理

二.宏定义用法

①宏常量

#include"stdio.h" #define PI 3.14 #define STR "圆周率约等于" int main() { 
    printf("%s %f",STR,PI); //预处理时会被替换为 printf("%s %f","圆周率约等于",3.14); return 0; } 

②宏语句

#include"stdio.h" #define Print printf("hello world!") int main() { 
     Print; //预处理时会被替换为 printf("hello world!"); return 0; } 

③宏函数

#include"stdio.h" #define Print(str) printf("%s",str) int main() { 
     Print("这是一个只有一条语句的宏函数!"); //预处理时会被替换为 printf("%s","这是一个只有一条语句的宏函数!") return 0; } 

在这里插入图片描述

④其它

1.#undef 是用来撤销宏定义的,用法如下:

#define PI 3. ... // code #undef PI //下面开始 PI 就失效了 

2.使用ifndef防止头文件被重复包含和编译

  这是宏定义的一种,它可以根据是否已经定义了一个变量来进行分支选择,一般用于调试等等.实际上确切的说这应该是预处理功能中三种(宏定义,文件包含和条件编译)中的一种—-条件编译。 C语言在对程序进行编译时,会先根据预处理命令进行“预处理”。C语言编译系统包括预处理,编译和链接等部分。

#ifndef x //先测试x是否被宏定义过 #define x //如果没有宏定义下面就宏定义x并编译下面的语句 ... ... ... #endif //如果已经定义了则编译#endif后面的语句 

所以还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的:

#ifndef <标识> #define <标识> ...... #endif 

<标识>
在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h

#ifndef _STDIO_H_ #define STDIO_H ... #endif #ifndef xxx //如果没有定义xxx #define xxx //定义xxx #endif //结束如果 

这个用法主要是在头文件中,主要是为了防止类重复的include,所以在类的头文件之前加上前面两个,用类名替代xxx,在最后加上最后一句

三.宏定义相关作用符

①换行符 “\n”

#include"stdio.h" #define Print printf("这是第1条语句\n"); printf("这是第2条语句\n"); printf("这是第3条语句\n") #define Show(str1,str2,str3) { 
       printf(%s\n”,str1); printf(%s\n”,str2); printf(%s\n”,str3); } int main() { 
       Print; //无参数宏函数 Show(“first”,“second”,“third”); //带参数宏函数 return 0; } 

②字符串化符 “#”

#include"stdio.h" #define Print(str) { 
       printf(#str"的值是%d",str); } int main() { 
       int x=3,y=4; Print(x+y); //此处等价于printf("x+y""的值是%d",x+y); //#str等价于"x+y",所以#str不需要再用双引号引起来  return 0; } 

③片段连接符””

#include"stdio.h" #define Add(n,value) { 
        numn+=value; } int main() { 
        int num1=1; int num2=10; Add(2,10); //等价于num2+=10; 这里把num和2连接成了num2  printf(" num1=%d\n num2=%d",num1,num2); return 0; } 

四.宏函数的巧用

①类型传递

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

这个时候,我们只有把类型,容量作为参数传递进行,就可以开辟各种类型的内存了

int *p=Malloc(int,100); //开辟int类型的内存 char *q=Malloc(char,100); //开辟字符类型的内存 

②传递数组

#include"stdio.h" #define InsertSort(list) { 
        int s=sizeof(list)/4; int i,j; for(i=2;i<=s;i++) { 
        list[0]=list[i]; for(j=i-1;list[j]>list[0];j--) list[j+1]=list[j]; list[j+1]=list[0]; } } int main() { 
        int num[]={ 
       0,2,5,7,3,1,8,0,8,22,57,56,74,18,99,34,31,55,41,12,9,4}; InsertSort(num); for(int i=1;i<sizeof(num)/4;i++) printf("%d ",num[i]); return 0; } 

五.注意事项

① 运算符优先级问题

#define MULTIPLY(x, y) x * y 

这是一个很简单的乘法函数,当计算MULTIPLY(10, 10),结果是100,这个大家都知道,但是当你计算MULTIPLY(5+5, 10)时,你以为结果还是100吗?当然不是,MULTIPLY(5+5, 10)=5+5*10=55,所以结果是55,所以我们写宏函数时要特别注意运算符的优先级,这里稳妥一点的写法应该这样写

#define MULTIPLY(x, y) ((x)*(y)) 

②宏参数重复调用

#define MAX(a,b) ((a)>(b)?(a):(b)) int a=0; int b =1; int c =MAX(++a,++b); 

这里很多人都以为是c=MAX(1,2)=2;而实际上上面代码等价于

int c =((++a)>(++b)?(++a):(++b)); 

可以看到实际上a b都各自加了两次,所以c=1>2?2:3=3,所以结果是3

③分号吞噬问题

#include"stdio.h" #define FUN(n) { 
        while(n>0) { 
        if(n==3) break; } } int main() { 
        int num=10; if(num>0) FUN(num); else num=-num; return 0; } 
#define FUN(n) do { 
        while(n>0) { 
        if(n==3) break; } }while(0) 

④递归调用问题

#define NUM (4 + NUM) 

  按前面的理解,(4 + NUM)会展开成(4 + (4 + NUM)),然后一直展开下去,直至内存耗尽。但是,预处理器采取的策略是只展开一次。也就是说,NUM只会展开成(4 + NUM),而展开之后NUM的含义就要根据上下文来确定了。

⑤宏参数预处理

  宏参数中若包含另外的宏,那么宏参数在被代入到宏体之前会做一次完全的展开,除非宏体中含有#或。

有如下宏定义:

#define A(y) X_y #define B(y) A(y) #define SIZE 1024 #define S SIZE 








版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/225036.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 上午10:16
下一篇 2026年3月17日 上午10:16


相关推荐

  • Aliyun平台Nginx+Mysql+Redis部署easyboot

    Aliyun平台Nginx+Mysql+Redis部署easyboot注册阿里云,免费申领一台云服务器地址https://free.aliyun.com/?spm=5176.10695662.7708050970.1.28142c4fKrKBP8新人特惠-购买一台云服务器ECShttps://www.aliyun.com/activity/new?spm=5176.12901015.d71.d71.4ea4525cvsDqbO&scm=20140722.3873.7.3972安装jdk,配置环境变量下载,上传jdk-8u202-linux-x64.t

    2022年7月26日
    6
  • 让 AI 听你的:Claude Code Hooks 完整指南与自动化教程

    让 AI 听你的:Claude Code Hooks 完整指南与自动化教程

    2026年3月15日
    2
  • pycharm安装与注册

    pycharm安装与注册安装选择好自己的安装路径后 点击 NEXT 这里把所有勾给打上 后面一直点击 next 直到安装完成 注册双击运行刚才安装的软件后面就点击 next 和 accept 就好了先点击第一步在点击第二步然后点击 continue 进行到下一步 下一步把安装包拖进来点击 restart 在点击为 pycharm 安装 点击是就好创建一个项目后可以进入菜单查看使用时间可以看到使用时间到 2089 年了 就安装注册好了

    2026年3月27日
    1
  • Yourphp系统发生错误

    Yourphp系统发生错误

    2021年10月9日
    57
  • 基于SSM实现的旅游管理系统【附源码】(毕设)[通俗易懂]

    基于SSM实现的旅游管理系统【附源码】(毕设)[通俗易懂]一、项目简介本项目是一套基于SSM实现的旅游管理系统或旅游网站或旅游社交平台或旅游景点管理系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。详细介绍了该系统的具体实现,包括:项目介绍环境搭建系统功能技术实现项目运行功能演示以通俗易懂的方式,手把手的带你从零开始部署并运行本套系统,该项目附带全部源码可作为毕设使用。项目都经过严格调试,确保可以运行!课程包含:项目源码、项目文档、数据库脚本、软件工具等所有资料带你从零开始部署运行本套系统

    2022年5月6日
    211
  • 【数据结构】连通图、连通分量与强连通图、强连通分量—区别在于强,强强在哪里?

    【数据结构】连通图、连通分量与强连通图、强连通分量—区别在于强,强强在哪里?如果 G 是有向图 那么连接 i 和 j 的路径中所有的边都必须同向 如果图中任意两点都是连通的 那么图被称作连通图 如果此图是有向图 则称为强连通图 注意 需要双向都有路径 今天叶子为大家分享的是 连通图 连通分量与强连通图 强连通分量

    2026年3月19日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号