将 __asm 块定义为 C 宏

Microsoft 专用

利用 C 宏,可以轻松将程序集代码插入源代码中,但执行此操作时要格外小心,因为宏会扩展到单个逻辑行中。 若要创建可靠的宏,请遵循以下规则:

  • __asm 块括在大括号内。

  • __asm 关键字放在每个程序集指令的前面。

  • 使用旧式 C 注释 (/* comment */) 而不是程序集样式的注释 (; comment) 或单行 C 注释 (// comment)。

为了演示这一点,下面的示例定义一个简单的宏:

#define PORTIO __asm      \
/* Port output */         \
{                         \
   __asm mov al, 2        \
   __asm mov dx, 0xD007   \
   __asm out dx, al       \
}

乍一看,最后三个 __asm 关键字是多余的。 但它们是必需的,因为宏将扩展到单个行中:

__asm /* Port output */ { __asm mov al, 2  __asm mov dx, 0xD007 __asm out dx, al }

需要将第三个和第四个 __asm 关键字作为语句分隔符。 在 __asm 块中识别的唯一语句分隔符是换行符和 __asm 关键字。 由于定义为宏的块是一个逻辑行,因此您必须使用 __asm 分隔每个指令。

大括号也是必需的。 如果省略它们,则编译器会对同一行上的 C 或 C++ 语句与宏调用的右侧内容混淆不清。 在没有右大括号的情况下,编译器无法告知程序集代码停止的位置,并且会将 __asm 块后面的 C 或 C++ 语句视为程序集指令。

以分号 (;) 开头的程序集样式注释将继续,直到达到行尾。 这会导致宏出现问题,因为编译器将忽略注释后面的内容,直到到达逻辑行尾。 上述情况同样适用于单行 C 或 C++ 注释 (// comment)。 若要防止错误,请在定义为宏的 /* comment */ 块中使用旧式 C 注释 (__asm)。

编写为 C 宏的 __asm 块可以采用自变量。 但与普通 C 宏不同,__asm 宏不能返回值。 这样您便无法在 C 或 C++ 表达式中使用这些宏。

请注意,不要任意调用此类型的宏。 例如,调用使用 __fastcall 约定声明的函数中的汇编语言宏可能会导致意外的结果。 (请参阅在内联程序集中使用和保留寄存器。)

结束 Microsoft 专用

另请参阅

内联汇编程序