聊一聊CLR源码中的 #define 是怎么玩的

一:背景

如果大家看过 CLR 源码,会发现里面有很多 #define 宏定义,比如说 fusionhelpers.hpp 头文件里。.

聊一聊CLR源码中的 #define 是怎么玩的

 

如果你不熟悉 C ,看到这些 #define 应该会很晕的,这篇我们就来简单聊聊 define 的玩法,其实说白了很简单, #define 就是用一个标识符来包装一段 常量 或者 函数体,后续要复用这段逻辑时只需用此 标识符 即可。

这里要注意的是:替换发生在 编译时,如果不相信的话,可以从汇编上做验证。

二:define 的简单使用

1. 用 define 定义常量

这个是最常用的,上一段简单的测试代码:

#include <iostream>

#define N 10

int main()
{
 printf("output: s=%d", N);
}

output: s=10

接下来我们探究下它的汇编代码。

00531921  push        0Ah  
00531923  push        offset string "s=%d" (0537B30h)  
00531928  call        _printf (05310D2h)  
0053192D  add         esp,8  

从汇编中可以看出,并没有出现 N 标识符的影子,而是直接将立即数 10 推送到栈上,大概就是下面这样。

printf("s=%d", 10);

相信大家也看到了这个简单替换,如果你还不信的话,我来演示一个 简单替换 的坑,参考如下代码:

#include <iostream>

#define N 10+2

int main()
{
 float f = N / 2;
 printf("output: s=%.1f", f);
}

output: s=11.0

哈哈,你是不是天真的以为上面的输出是 s=6 ? 那就大错特错了,这个例子很好的反向证明了 确实是 替换 所致。

接下来我们来看下底层汇编是咋样的。

00f11925  movss   xmm0, dword ptr [ConsoleApplication1!_real (00f17b44)]
00f1192d  movss   dword ptr [ebp-8], xmm0

0:000> dp 00f17b44 L1
00f17b44  41300000

0:000> .formats 41300000
Evaluate expression:
  Hex:     41300000
  Decimal: 1093664768
  Octal:   10114000000
  Binary:  01000001 00110000 00000000 00000000
  Chars:   A0..
  Time:    Sat Aug 28 11:46:08 2004
  Float:   low 11 high 0
  Double:  5.40342e-315

从汇编代码看,f 的值已经算好了存放在 00f17b44 地址上,值为 41300000, 通过 .formats 命令可以看出 41300000 转成 float 就是 11,很好的证明了它是在编译时就已经处理好了。

有了这些基础,改进方案就简单了,用 () 将 define 体包装一下即可,参考如下:

#define N (10+2)

2. 用 define 定义函数

从 CLR 源码上看,不仅仅可以定义 常量,还可以定义复杂的函数,接下来我们就演示一下。

#include <iostream>

#define SUM(a,b) a+b

int main()
{
 int a = 10;
 int b = 20;

 int sum = SUM(a, b);

 printf("output: sum=%d", sum);
}

output: sum=30

然后再看一下 int sum = SUM(a, b) 的汇编代码。

00581925  mov         dword ptr [ebp-8],0Ah  
0058192C  mov         dword ptr [ebp-14h],14h  
00581933  mov         eax,dword ptr [ebp-8]  
00581936  add         eax,dword ptr [ebp-14h]  

可以看到,那个 Sum 方法直接被 inline 了,高效哈,如果语句多的话,也可以在  #define 中用  {} 括起来,比如下面这样。

#include <iostream>

#define SUM(a,b) {int i=a; int j=b; printf("output: %d+%d=%d",i,j,(i+j));}

int main()
{
 int a = 10;
 int b = 20;

 SUM(a,b);
}

output: 10+20=30

好了,今天就聊这么多,希望对大家有帮助!