C++ 中的宏定义和内联函数作用相似,本篇就来介绍这两个的使用以及不同。

# 宏定义

宏定义使用 define 关键字,有两种格式:宏名称以及名称 + 文本,后者还可以分为有参和无参。

# 宏名称

只有宏名称的一般用来标记头文件,为了防止编译时对相同的文件编译两遍,在第二次遇到相同的宏定义时就会跳过。

#ifndef HEADER_H
#define HEADER_H
#endif

# 名称 + 文本

在编译时期就会将名称替换为对应的文本,下面第一个定义了一个变量,如果不进行初始化就访问则会报错。而 A 和 a 其实都是一个,都会被认为是 a,所以再次初始化变量 a 也会报错。
在定义有参数的宏时,注意要加上括号,因为在替换的时候是直接进行的文本替换,并不会考虑优先级等,否则结果就是错的。

#include <iostream>
#define A a
#define B 10
#define C false
#define D 'a'
#define E "aaaa"
#define ADD(x, y) (x + y)
#define ADD_E(x, y) x + y
using namespace std;
int main() {
  // cout << A << endl; error: Use of undeclared identifier 'a'
  int A = 1;
  // int a = 2; error: Redefinition of 'a'
  cout << A << endl; // 1
  cout << a << endl; // 1
  cout << B << endl; // 10
  cout << C << endl; // 0
  cout << D << endl; // a
  cout << E << endl; // aaaa
  cout << ADD(1, 2) << endl; // 3
  cout << ADD_E(1, 2) * 3 << endl; // 7
}

# 特殊字符

# \ & # & ##

\ 是换行符。 # 符号将参数转换为加了双引号的值,所以 get_name () 输出是 "name"。 ## 将参数当做普通字符串与其他文本连接,所以成员变量分别为 age_ 和 name_,函数分别为 get_age () 和 get_name ()。
另外也看到有 #@ ,不过我试了编译会报错: '#' is not followed by a macro parameter

#include <iostream>
#include <string>
#define CLASS(class_name, field_1, field_2) \
class class_name { \
 private: \
  int field_1##_; \
  string field_2##_; \
 \
 public: \
  class_name(int field_1##_val) { \
    field_1##_ = field_1##_val; \
    field_2##_ = #field_2; \
  } \
 \
  ~class_name() {} \
 \
  int get_##field_1() { \
    return field_1##_; \
  } \
 \
  string get_##field_2() { \
    return field_2##_; \
  } \
};
using namespace std;
CLASS(person, age, name)
int main() {
  person* p = new person(10);
  cout << p->get_age() << endl; // 10
  cout << p->get_name() << endl; // name
}

# VA_ARGS

__VA_ARGS__ 代表可变个数参数, ##__VA_ARGS__ 代表参数个数可为 0。

#include <iostream>
#define sum(a, ...) add(a, __VA_ARGS__)
#define sum1(a, ...) add(a, ##__VA_ARGS__)
using namespace std;
int add(int a) {
  return a;
}
int add(int a, int b) {
  return a + b;
}
int add(int a, int b, int c) {
  return a + b + c;
}
int main() {
  // cout << sum(1) << endl; error: Expected expression
  cout << sum(1, 2) << endl; // 3
  cout << sum(1, 2, 3) << endl; // 6
  // cout << sum(1, 2, 3, 4) << endl; error: No matching function for call to 'add'
  cout << sum1(1) << endl; // 1
  cout << sum1(1, 2) << endl; // 3
  cout << sum1(1, 2, 3) << endl; // 6
}

# 内联函数

内联函数是在普通函数前面加上 inline ,会替换函数,这样就避免了运行时调用的开销。这种情况是定义与调用是分开的情况,当函数调用的开销不小于函数执行的开销时,适合使用内联函数。

test1.cpp
#include <iostream>
inline void print() {
  std::cout << "inline." << std::endl;
}
test.cpp
#include <iostream>
#include "test1.cpp"
int main() {
  print(); // inline
}

# 不同

  1. 语义。define 只是进行文本替换,而 inline 则是定义函数。
  2. 类型检查。define 完全是傻瓜式替换,inline 会进行类型检查。
  3. 调试。inline 是可以调试的。