相信很多人入门时都使用 MASM,这的 MASM 就是 Microsoft‘s Macro Assembler。其中的 Macro 就是宏的意思。相比函数,宏具有更加简洁,运行速度快(编译器会对代码进行“宏展开”,直接修改代码)等等特点。但是,如果需要调试和阅读具有多层宏定义就非常痛苦了。很多年前我接触到的P公司的BIOS代码就是这样,乍一看代码非常规整,每一行就像一个洋葱,追踪起来一层又一层,让人感叹阅读代码是个系统工程。
最近偶然看到 GCC 有展开宏功能,同样的在Microsoft 的Visual C++上也有类似功能,通过编译指令 /p 或者 /ep 即可实现。这两个参数的区别在于生成的” 预编译文件”是否有行号。例如,编写下面的代码,其中定义一个名为 SUM 的宏:
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#define SUM(a,b) a+b
/***
Print a welcoming message.
Establishes the main structure of the application.
@retval 0 The application exited normally.
@retval Other An error occurred.
***/
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
int c =3,d=4;
Print(L"Hello there fellow Programmer.\n");
Print(L"Welcome to the world of EDK II.\n");
Print(L"Macro test %d\n",SUM(c,d));
return(0);
}
在 INF 中定义如下:
[BuildOptions]
MSFT:*_*_X64_CC_FLAGS = /P
在Build 目录下有生成一个 hello.i 其中有如下代码断,可以看到 SUM 宏已经展开。
INTN
__cdecl
ShellAppMain (
UINTN Argc,
CHAR16 **Argv
)
{
int c =3,d=4;
Print(L"Hello there fellow Programmer.\n");
Print(L"Welcome to the world of EDK II.\n");
Print(L"Macro test %d\n",c+d);
return(0);
}
如果使用 /EP /P 参数,那么生成的预编译文件中不会有行号:
[BuildOptions]
MSFT:*_*_X64_CC_FLAGS = /EP /P
下图中,左侧是 /EP /P 参数的运行结果,右侧是/P 的结果: