1.6 运行第一个MASM和C++的混合程序
本书通常将汇编语言模块(包含一个或多个使用汇编语言编写的函数)与调用它的C/C++主程序相结合。由于由汇编语言和C++语言组成的混合程序的编译及执行过程与独立MASM程序的略有不同,因此本节将演示如何创建、编译和运行这样一个混合程序。程序清单1-2提供了调用汇编语言模块的C++主程序。
程序清单1-2 示例C/C++程序(listing1-2.cpp文件),该程序调用了汇编语言函数
//程序清单1-2
//一个简单的C++程序,该程序调用了一个使用汇编语言编写的函数。
//需要包含stdio.h头文件,以便程序能够调用“printf”函数。
#include<stdio.h>
//extern“C”命名空间可以防止C++编译器的“名称篡改”。
extern"C"
{
//以下是使用汇编语言编写的外部函数,本程序将调用该函数:
void asmFunc(void);
};
int main(void)
{
printf("Calling asmMain:\n");
asmFunc();
printf("Returned from asmMain\n");
}
程序清单1-3是可独立运行MASM程序的改进版,其中包含asmFunc()函数,此函数被C++程序调用。
程序清单1-3 MASM程序(listing1-3.asm文件),被程序清单1-2中的C++程序调用
;程序清单1-3
;一个简单的MASM模块,包含一个空函数,被程序清单1-2中的C++代码调用。
.CODE
;(有关option伪指令的说明,请参见后续正文。)
option casemap:none
;以下是“asmFunc”函数的定义。
public asmFunc
asmFunc PROC
;空函数,直接返回到C++代码。
ret;返回到调用方
asmFunc ENDP
END
相对于原始的programShell.asm源文件,程序清单1-3包括三处修改。首先,有两个新的语句,即option语句和public语句。
option语句指示MASM将区分所有符号的大小写。这是非常必要的操作,因为在默认情况下,MASM不区分大小写,并将所有标识符映射为大写(意味着asmFunc()函数将转换为ASMFUNC())。而C++是区分大小写的程序设计语言,会将asmFunc()和ASMFUNC()视为两种不同的标识符。因此,必须指示MASM区分标识符的大小写,以免混淆C++程序的语义。
注意:MASM标识符可以以美元符号($)、下划线(_)或字母字符开头,后面跟零个或多个字母、数字字符、美元符号或下划线字符。标识符本身不能由$字符组成($符号在MASM中具有特殊意义)。
public语句声明asmFunc()标识符将对MASM源文件和目标文件的外部可见。如果没有该语句,那么只能在MASM模块内访问asmFunc(),C++编译就会报错:asmFunc()是一个未定义的标识符。
程序清单1-3和程序清单1-1之间的第三个区别是,函数名从main()更改为asmFunc()。如果在汇编代码中使用名称main(),则由于C++程序中也包含一个名称为main()的函数,因此C++编译器和链接器会出现混乱。
为了编译和运行这些源文件,可以使用如下所示的命令:
ml64命令使用了“/c”选项,该选项表示“仅编译”,并且不尝试运行链接器(如果运行链接器则将失败,因为listing1-3.asm不是一个可独立运行的程序)。MASM的输出是一个目标代码文件(listing1-3.obj),该文件作为下一个命令中Microsoft Visual C++(MSVC)编译器的输入。
cl命令在listing1-2.cpp文件上运行MSVC编译器,并将汇编代码(listing1-3.obj)进行链接。MSVC编译器的输出是一个可执行文件listing1-2.exe,从命令行执行该程序就会产生预期的输出结果。