C/C++中宏定义(#define)

#define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用该命令,使得程序的运行与预期的目的不一致,或者在读别人写的程序时,把运行结果理解错误,这对 C语言的学习很不利。

宏的定义在程序中是非常有用的,但是使用不当,就会给自身造成很大的困扰。通常这种困扰为:宏使用在计算方面。

本例子主要是在宏的计算方面,很多时候,大家都知道定义一个计算的宏,对于编译和编程是多么的有用。现在定义有以下一个计算 “乘法” 的宏。

#include <stdio.h>
#define MUL(a) ((a)*(a)*(a))
int main(int argc,char *argv[])
{
 int i = 10;
 int sum = MUL(i);
 printf("MUL(%d) = %d\n",i,sum);
 return 0;
}
</stdio.h>

  上面程序的这种做法对于非负数而言那就是没有问题的,比如,程序中的 变量 i=10,这个时候,调用宏得到的数据如下:

  但是如何变量的数值是自加或者自减的操作的话,结果就不一样了。

  假如我们将上面的程序变为下面这样的

#include <stdio.h>
#define MUL(a) ((a)*(a)*(a))
int main(int argc,char *argv[])
{
 int i = 10;
 int sum = MUL(++i);
 printf("MUL(%d) = %d\n",i,sum);
 return 0;
}
</stdio.h>

  得到的结果并不是 11 * 11 *11 = 1331这个数据,而是 1872,这时候有人会问为什么?

  得到宏的朋友或者了解过宏在计算方面的朋友就会知道,这除了是宏的问题,还是本身程序员编写这段代码的问题。当使用了 ++i 和 i++ 的时候,

要特别注意在宏中是全部使用 ++i或者i++的,变成的格式如下

MUL(i++) ((i++)*(i++)*(i++))
 MUL(++i) ((++i)*(++i)*(++i))

  上述的做法显然不是我们想要的计算结果,可能在我们程序中看到的是MUL(++i) 或者 MUL(i++),认为实际上是如下情况:

//当i的初始化数值为10的时候,进行i++的 MUL(i++)宏计算,即是:int i = 10;
//MUL(i ++)的数值计算结果相比是 10 * 11 * 12的,这是没有问题的,但是 i的值呢??是11吗??显然不是。    MUL(i++) = 10 * 11 *12;i = ??;

  i的数值如下图所示

  诚然,i的数值变成了 13,这是为什么呢??

  那就是因为这个MUL(a)这个宏和程序员的 “自加自减” 操作所造成的。这里先普及一下 C/C++语言的 “自加自减” 操作:

//自加自减的操作

i++ 和 ++i  ----> 这里的操作属于++后操作,可以替换成 i = i+1 的结果。

但是,当它赋值给一个变量的时候,表示的内容和含义就有不同: (假设i = 10)

1.  sum1 = i++;

2.  sum2 = ++i;

1中的sum1的数值就是 10, i为 11

2中的sum2的数值就是 11, i为 11

这是因为:

i++ 操作是 先赋值给 sum1后,自己在执行 i = i+1的操作

++i 操作是 先进行 i = i+ 1的操作,然后再赋值给sum2

这样得到的结果当然不同了,但是i最终的结果是要加1的,只不过是赋值给变量的时候会有不同

  通过对自加自减的操作进行说明,不知道大家是否明白为什么了吗??

当 i  = 10的时候,MUL(i++)就是为  (i++)*(i++)*(i++)的计算结果,考虑到C/C++的运算符结合性,

先计算第一个 i++,这是一个先计算后赋值的自加方式,那么这是后第一个 (i++)的数值待定为 10 ,那么第

二个的i是因为第一个数据的 (i++)起了作用而变化的,这时候第二个(i++)的数值为11,然后加1,这时候 根

据结合性,先计算前面两个数据,就是(i++) * (i++)的数值了,即为:10 * 11了,这时候的i数值是 12;

然后计算第三个 i++的数值,这时候第三个i++中的i数值为 12,计算后再加1,也就是说,10 * 11 * 12之后,

i= 12 的数值在进行i++变为 13了。所以  MUL(i++) = 10 * 11 * 12 = 1320。   

  另外,在进行++i的操作和上述的情况差不多,只不过是先做自加的运算,在进行赋值。

当 i = 10的时候,MUL(++i)实际上也为 (++i)*(++i)*(++i)的方式,这时候先计算第一个 (++i),这是一

个先计算后赋值的结合方式,那么 i = i+1 = 11;这时候准备计算第二个(++i)的时候,因为需要先计算后赋值,

所以 第二个 ++i 之后的数值为12,但是因为i属于同一个变量和属性,那么第一个i也会变成 12了,这时候结合性

考虑应该是计算前两个(++i)的结果,再与第三个(++i)计算,即(++i)*(++i) = 12 * 12;然后,我们计算第三个

(++i)的数值,由于前面第二个++i的i值,所以第三个++i即为 13,此时,12 * 12 * 13。

  有人可能顾虑,为什么最后不是13 * 13 * 13的呢?那不是最后都是13吗??  ------》其实这种想法是错误的,

这必须先理解运算符的结合性。我们知道,当计算中遇到了括号的时候,我们先计算括号的内容,这是我们在数学中的惯性思维。但是对于计算机而言,计算机必须 有计算的优先级,也就是运算符的优先级问题。首先我们计算前面两个括号的内容,以为两个括号之间有乘号(*),所以计算前面两个(++i)之后,必须进行乘法计算,这就是优先级中的乘法计算,自左向右计算。所以结果变为了 12 * 12的最终结果在和第三个括号的(++i)计算,就是144 * (++ i) = 144 * 13;

  所以MUL(++i)的结果如下:

总结:

  慎用宏在计算方面的,但是宏的有点还是很多的,对于C语言来说,宏可以减少运行的时间。在C++中,宏由于不会对类型进行检查,安全性不够,所以建议使用const来

进行使用,这样可以保证类型一致。这是C/C++对宏的严谨性进行优化的结果。

以上所述是小编给大家介绍的C/C++中宏(#define)定义知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • C/C++宏定义的可变参数详细解析

    编写代码的过程中,经常会输出一些调试信息到屏幕上,一般会调用printf这类的函数.但是当调试解决之后,我们需要手工将这些地方删除或者注释掉.最近在看<Linux C编程一站式学习>这本书,就想到一个方法: 复制代码 代码如下: void myprintf(char* fmt, ...){}#ifdef DEBUG#define printf(fmt, args...) myprintf(fmt, ##args)#endif 调试阶段带着DEBUG调试,正式上线就可以把printf变成一个空函

  • C/C++ 宏详细解析

    众多C++书籍都忠告我们C语言宏是万恶之首,但事情总不如我们想象的那么坏,就如同goto一样.宏有一个很大的作用,就是自动为我们产生代码.如果说模板可以为我们产生各种型别的代码(型别替换),那么宏其实可以为我们在符号上产生新的代码(即符号替换.增加). 关于宏的一些语法问题,可以在google上找到.相信我,你对于宏的了解绝对没你想象的那么多.如果你还不知道#和##,也不知道prescan,那么你肯定对宏的了解不够. 我稍微讲解下宏的一些语法问题(说语法问题似乎不妥,macro只与preproc

  • C/C++语言宏定义使用实例详解

     C/C++语言宏定义使用实例详解 1. #ifndef 防止头文件重定义 在一个大的软件工程里面,可能会有多个文件同时包含一个头文件,当这些文件编译链接成 一个可执行文件时,就会出现大量"重定义"的错误.在头文件中实用#ifndef #define #endif能避免头文件的重定义. 方法:例如要编写头文件test.h 在头文件开头写上两行: #ifndef TEST_H #define TEST_H //一般是文件名的大写 头文件结尾写上一行: #endif 这样一个工程文件里同时

  • C/C++中宏定义(#define)

    #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用该命令,使得程序的运行与预期的目的不一致,或者在读别人写的程序时,把运行结果理解错误,这对 C语言的学习很不利. 宏的定义在程序中是非常有用的,但是使用不当,就会给自身造成很大的困扰.通常这种困扰为:宏使用在计算方面. 本例子主要是在宏的计算方面,很多时候,大家都知道定义一个计算的宏,对于编译和编程

  • C语言宏定义#define的使用

    目录 无参宏定义 定义形式 带参宏定义 定义形式 #和##运算 #运算 用法: ##运算 用法: 变参宏 #ifndef 条件编译 宏定义是高级语言编译器提供的常用语法,其目的是利用某一标识符标识某个文本字符串.在编写程序时,如果程序中反复地使用某个数据或某段程序片段,就可以考虑将这个数据或程序片段定义为宏,然后每个出现该数据或程序片段的地方用宏名替代,选择宏定义来做的好处是程序简洁,可读性好,而且当需要修改这些相同的程序片段时,只要修改宏定义中的字符串即可,不需要修改多处. 宏定义命令:def

  • C语言中的内联函数(inline)与宏定义(#define)详细解析

    先简明扼要,说下关键:1.内联函数在可读性方面与函数是相同的,而在编译时是将函数直接嵌入调用程序的主体,省去了调用/返回指令,这样在运行时速度更快. 2.内联函数可以调试,而宏定义是不可以调试的.内联函数与宏本质上是两个不同的概念如果程序编写者对于既要求快速,又要求可读的情况下,则应该将函数冠以inline.下面详细介绍一下探讨一下内联函数与宏定义. 一.内联函数是什么?内联函数是代码被插入到调用者代码处的函数.如同 #define 宏(但并不等同,原因见下文),内联函数通过避免被调用的开销来提

  • C语言中宏定义使用的小细节

    #pragma#pragma 预处理指令详解 在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和 C++语言完全兼容的情况下,给出主机或操作系统专有的特征.依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的. 其格式一般为: #Pragma Para.............etc.. baike.baidu.com/view/1451188.htm

  • C语言中宏定义的妙用方法

    最近看了intel在linux内核中的驱动,学习到了一个非常有用的小技巧,如下代码: #define IN #define OUT #define UAdress volatile unsigned int * #define Raw_buffer void * void SetHwiPortsDataReg(IN UAdress Register , IN int value) { _SetHwiPortsDataReg(Register,&value); } void _Out_Put_va

  • C语言中#define在多行宏定义出错的原因及分析

    目录 C语言中#define在多行宏定义出错的原因 1.第一种错误 2.第二种错误 使用#define宏定义的几个小技巧 1.调试开关 2.条件编译 3.宏实现函数 4.跨行宏定义 5.防止头文件被重复包含 6.带参宏与带参函数的区别 7.注意事项 总结 C语言中#define在多行宏定义出错的原因 1.第一种错误 #include<stdio.h> #define echange(a,b) {\/*宏定义中允许包含多行命令的情形,此时必须在最右边加上"\"*/  int

  • C语言#define拼接宏定义实现方式

    使用场合:拼接两个宏,一个是传入的宏.但是传入的宏不会被替换,反而原封不动的接了上去,这就尴尬了.经过各种尝试,居然成了,特此记录分享一下,方便大家学习. char A_param=0; char B_pramm=0; //添加宏定义 #define OBJECT A #define DEFINE_(X) X##_param //一次定义 #define DEFINE(X) DEFINE_(X) //再次定义 #define PARAM DEFINE(OBJECT) void fun() { /

  • 一文带你搞懂C语言预处理宏定义

    目录 预定义符号 #define #define 定义标识符 #define 定义宏 替换规则 # 和## 预定义符号 这些预定义符号都是语言内置的 __FILE__ //进行编译的源文件 __LINE__ //文件当前的行号 __DATE__ //文件被编译的日期 __TIME__ //文件被编译的时间 __STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义 VS环境下未定义__STDC__ ,说明Visual Studio并未完全遵循ANSI C. #define #defi

  • C语言宏定义容易认不清的盲区梳理

    目录 1.概念 3.宏不是函数 4.宏定义不是说明或语句 5.宏不是类型定义 6.与之相关的宏定义 7.总结 1.概念 #define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本. 命令有两种格式:一种是简单的宏定义,另一种是带参数的宏定义. (1)简单的宏定义: #define<宏名> <字符串> #defineVALUE((sizeof(a))/sizeof(a[0])) (2) 带参数的宏定义 #defin

  • 详解C语言中的#define宏定义命令用法

    #define 命令#define定义了一个标识符及一个串.在源程序中每次遇到该标识符时,均以定义的串代换它.ANSI标准将标识符定义为宏名,将替换过程称为宏替换.命令的一般形式为: #define identifier string 注意: 1.该语句没有分号.在标识符和串之间可以有任意个空格,串一旦开始,仅由一新行结束. 2.宏名定义后,即可成为其它宏名定义中的一部分. 3.宏替换仅仅是以文本串代替宏标识符,前提是宏标识符必须独立的识别出来,否则不进行替换.例如: #define XYZ t

随机推荐