宏和函数

宏通常被应用于执行简单的运算。比如在两个数中找出较大的一个。

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

那为什么不用函数来完成这个任务,原因又两点:

  1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。
  2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的。

当然宏相比函数也有劣势的地方:

  1. 每次使用宏的时候,一份定义宏的代码插入到程序中,除非宏比较短,否则可能大幅度增加程序的长度。
  2. 宏是没法调试的
  3. 宏由于类型无关,也不够严谨
  4. 宏可能会带来运算符优先级的问题,导致程容易出现错。

宏有时候可以做函数做不到的事情。比如:宏的参数可以出现类型,但是函数做不到。

#define MALLOC(num, type)\
(type *)malloc(num * sizeof(type))
...
//使用
MALLOC(10, int);//类型作为参数
//预处理器替换之后:
(int *)malloc(10 * sizeof(int));

宏和函数的一个对比

属性#define定义宏函数
代码长度每次使用时,宏代码都会被插入到程序中。函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码
执行速度更快存在函数的调用和返回的额外开销,所以相对慢一些
操作符优先级宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多些括号。函数参数只在函数调用的时候求值一次,它的结果值传递函数。表达式的求值结果更容易预测。
带有副作用的参数参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果。函数参数只在传参的时候求值一次,结果更容易控制。
参数类型宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型。函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是不同的。
调试宏是不方便调试的函数是可以逐语句调试的
递归宏是不能递归的函数是可以递归的
### 函数介绍 函数是看起来像函数调用的,比普通函数更加灵活,例如可以接收不定数量的参数。以Rust中的类函数为例,它获取TokenStream参数,其定义使用Rust代码操纵TokenStream。一个类似函数的例子是可以像这样被调用的sql!:`let sql = sql!(SELECT * FORM posts WHERE id=1);` [^1]。 ### 属性介绍 属性通常用于为结构体、枚举、函数等项添加额外的元数据或行为。它们可以在编译时修改代码的生成,常用于代码生成、自动实现特征等场景。比如在Rust的`serde`库中,`#[derive(Serialize, Deserialize)]`就是属性,它可以为结构体自动生成序列化反序列化的代码。 ### 区别 - **语法形式**:函数的调用形式类似函数调用,如`sql!(...)`;而属性以`#[...]`的形式附着在项的前面,如`#[derive(Serialize)] struct MyStruct {... }`。 - **功能侧重点**:函数主要用于根据输入的参数生成代码片段,更侧重于代码的复用灵活的参数处理;属性侧重于为项添加额外的编译时行为或元数据,对项本身进行修改或增强。 - **参数传递方式**:函数可以接收不定数量的参数,并且参数的处理通常在定义中进行;属性的参数通常是固定的,并且是在属性标记中指定,例如`#[attr(arg1, arg2)]`。 ### 使用场景 - **函数使用场景**:当需要根据不同的输入生成不同的代码片段,且输入参数数量不固定时,函数是一个很好的选择。例如,在编写数据库查询语句生成器时,可以使用函数根据不同的查询条件生成相应的SQL语句。 - **属性使用场景**:当需要为类型或函数添加一些通用的行为,如序列化、调试信息输出、自动实现特征等,属性可以大大简化代码。例如,在编写Web应用程序时,使用属性为数据模型自动生成JSON序列化反序列化代码。 ### 代码示例 #### 函数示例(Rust) ```rust macro_rules! add { ($a:expr, $b:expr) => { $a + $b }; } fn main() { let result = add!(3, 5); println!("Result: {}", result); } ``` #### 属性示例(Rust,使用`serde`库) ```rust use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize, Debug)] struct Person { name: String, age: u8, } fn main() { let person = Person { name: "John".to_string(), age: 30, }; let json = serde_json::to_string(&person).unwrap(); println!("JSON: {}", json); } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值