栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言:#define详解

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言:#define详解

#define定义标识符
语法: #define name stuff tips:我们在define定义标识符的时候,不建议在后面加上 ;,这样很容易出问题。比如说在以下的情况中: if ( condition ) max = MAX ; else max = 0 ;
 #define定义宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义 宏(define macro)。

宏的申请方式:#define name( parament-list ) stuff

其中的 parament - list 是一个由逗号隔开的符号表,它们可能出现在 stuff 中。 如果我们要写 #define SQUARE( x ) x * x 这样的一个宏。
#define SQUARE(x) x*x //参数列表的左括号必须与name紧邻

int main()
{
    int r = 5;
    printf("%dn", r);
    
    return 0;
}

打印出来的结果就是25。但是这样一个宏定义也存在着一定的问题。如果说我们传进去的值是5+1,那么它打印出来的结果会是11而不是36。

原因就在于5+1是替换掉宏定义中的x。就变成了int r = 5+1*5+1。只需要加上括号即可解决,#define SQUARE(x) ((x) * (x))。

 #define替换规则

                   在程序中扩展#define定义符号和宏时,需要涉及几个步骤。

1. 在调用宏时,首先对参数进行检查,看看是否包含任何由 #define 定义的符号。如果是,它们首先被替换。 2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。 3. 最后,再次对结果文件进行扫描,看看它是否包含任何由 #define 定义的符号。如果是,就重复上述处理过程。
#和## 

 #可以把参数插入到字符串中

#define PRINT(N) printf("the value of "#N" is %dn", N)

int main()
{
    int a = 10;
    PRINT(a);

    int b = 20;
    PRINT(b);

    return 0;
}

在N的前面加上#,N的参数不会替换成它本身,而是会转换成对应的字符。

##可以把位于他两边的符号合成一个符号

#define CAT(Class,Num) Class##Num

int main()
{
    int Class100 = 100;
    printf("%dn",CAT(Class,100)

    return 0;
}

 这个例子表达的是,CAT有两个参数,##会把两个参数合成一个符号,所以打印的就是100。

带副作用的宏参数 

 当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能 出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。

x + 1 ; // 不带副作用 x ++ ; // 带有副作用
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
...
x = 5;
y = 8; 
z = MAX(x++, y++);

printf("x=%d y=%d z=%dn", x, y, z);

最终的结果是:x=6,y=10,z=9 

宏和函数对比 
属 性 #define 定义宏 函数
代码长度 每次使用时,宏代码都会被插入到程序中。除了非常 小的宏之外,程序的长度会大幅度增长 函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码
执行速度 更快 存在函数的调用和返回的额外开 销,所以相对慢一些
操作符优 先级 宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多些括号。 函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预测。
带有 副作 用的 参数 参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果。 函数参数只在传参的时候求值一次,结果更容易控制。
参数 类型 宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型。 函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是 不同的。
调试 宏是不方便调试的 函数是可以逐语句调试的
递归 宏是不能递归的 函数是可以递归
命名约定 
一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。 那我们平时的一个习惯是:把宏名全部大写,函数名不要全大写。

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1025511.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号