如何在Visual C++
中使用汇编语言
今天,可能大多数的程序员都会对汇编语言怀有戒心,认为它是一种非常难理解及使用的语言,要么就认为它是老掉牙了,早就应该被更高级的语言取代。本文就是要消除大家心中的畏惧,其实它并不是很难于运用,正相反,文中还将演示了可极大地降低汇编语言使用难度的MASM,并怎样将它与Visual Studio集成。
首先,什么是汇编语言,今天还谈汇编语言有什么意义吗?简单来说,它是处理器的语言,没有比这更低级的语言了(除了那些指令的实际字节值);它的每条命令(mov、add等等)都由宏汇编程序(MASM)直接翻译为处理器执行的“数字”。
使用汇编语言的最大优势在于速度,这是一种完全原生、未受限制的速度,即使现在的编译器能够对代码进行优化,恐怕这些优化后的代码也难与手工编写、人工优化的汇编代码相抗衡。
当然了,汇编语言也不是每个地方都适用的,虽然可用汇编语言来编写整个程序,但与C++等今天其他高级语言相比,还是有点过于“自虐”了,就拿今天占绝对数量优势的应用程序来说,C++甚至.NET语言的速度,也是非常令人满意的。
所以,只有在极其看重速度的场合才适用汇编语言,比如说图形程序,在编写小型、快速寻址大块内存的函数上,汇编语言也是不可战胜的,位图操纵就是一个典型的例子。该说的也说得差不多了,下面来看看怎样使用它。
在Visual C++
中编写汇编代码
可使用 __asm语句块在Visual C++中编写汇编代码:
DWORD Function(DWORD dwValue)
{
__asm
{
mov eax, dwValue
add eax, 100
mov dwValue, eax
}
return dwValue;
}
在 __asm块中包含了一些汇编指令,C++编译器会把它们直接翻译成机器语言代码。以上代码的意思只是简单地把传递进来的数值加上100。
在 __asm块中编写一小点汇编代码还是可行的,但是要编写长一点的代码,那就变得单调乏味了,例如,一个“if…else”语句将会像下面这样:
DWORD Function2(DWORD dwValue1, DWORD dwValue2)
{
DWORD dwValue3 = 0;
#if 0
if (dwValue1 == dwValue2)
{
dwValue3 = 1;
}
else
{
dwValue3 = 2;
}
#endif
__asm
{
mov eax, dwValue1
; 此处对值进行比较,是否dwValue1 == dwValue2
cmp eax, dwValue2
; 如果不相等,跳到“Else”
jne Else
mov eax, 1
jmp EndIf
Else:
mov eax, 2
EndIf:
mov dwValue3, eax
}
return dwValue3;
}
如果每个if语句都要这样来写,人都可能要崩溃了。在 __asm块中写汇编代码,就像在记事本或命令行中写C++代码一样,枯燥而乏味,此时可以借助Microsoft Macro Assembler(MASM),它能生成与Visual C++链接器相兼容的 .obj文件,甚至在其中还能包含调试信息。使用了MASM之后,前面的代码就能像下面这样写:
Function proc dwValue1:DWORD, dwValue2:DWORD
mov eax, dwValue1
.if eax == dwValue2
mov eax, 1
.else
mov eax, 2
.endif
ret
Function endp
这样看上去可读性就高多了,下面就来看一下如何添加汇编文件到现有C++工程中,及在C++中如何访问汇编语言编写的函数。
添加汇编文件到Visual C++
中
以下说明以Visual C++ 6.0为例,其他版本的也类似。首先,需要包含MASM的bin文件夹,在Tools/Options/Projects/Visual C++ Directories中,添加“bin”文件夹,本文中为“C:/MASM32/bin”。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/xieqidong/An%20Introduction%20to%20Assembly%20Language1.jpg)
把这个目录移到最下端,这一点非常重要,因为这个目录中也有一个名为link.exe的链接程序,这样做是为了防止干扰Visual Studio的默认链接器。
现在,创建一个控制台程序。添加一个“test.asm”文件到工程中:在Solution Explorer中右键单击“source files”文件夹,选择Add/New Item。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/xieqidong/An%20Introduction%20to%20Assembly%20Language2.jpg)
输入“test.asm”后回车,现在一个“test.asm”的新文件就打开在你面前了。
在文件中输入以下代码:
486
.model flat, stdcall
option casemap :none
.code
TestProc proc dwValue:DWORD
mov eax, dwValue
add eax, 100
ret
TestProc endp
End
代码仍是把传递进来的值加上100,并返回其结果。
注意:所有的MASM汇编文件都需要包含最前面4行及最后的End,实际代码位于.code与End之间。
现在,设置文件的生成属性,在Debug模式中右键单击文件,并选择“properties”,接着选择“custom build step/general”,并在“command line”中输入以下:
ml /c /coff /Zi /Fo"$(OutDir)/$(InputName).asm.obj" "$(InputFileName)"
还要在“Outputs”下输入:$(OutDir)/$(InputName).asm.obj
如下图:
![](https://p-blog.csdn.net/images/p_blog_csdn_net/xieqidong/An%20Introduction%20to%20Assembly%20Language3.jpg)
Release模式与上面基本相同,除了编译行中没有/Zi选项,这个代表“generate debug info”,所以应为:ml /c /coff /Fo"$(OutDir)/$(InputName).asm.obj" "$(InputFileName)"。
从C++
中调用汇编代码
前面的汇编代码定义一个名为“TestProc”的函数,其接受一个DWORD(32位)的参数,所以在C++中调用之前,需先有一个函数定义。找到main函数的cpp文件,把下面一行添加在#include后面:
extern "C" unsigned int __stdcall TestProc(unsigned int dwValue);
在main函数中加入以下代码:
int main(int argc, _TCHAR* argv[])
{
unsigned int dwValue = 100;
unsigned int dwReturn = TestProc(dwValue);
printf("%d/n", dwReturn);
getchar();
return 0;
}
运行这个程序之后,返回的结果值将会是预期的200,另外,如果在调用TestProc处放置一个断点,就能单步调试这个方法,甚至可在汇编代码中放置断点。
看到这,觉得在VC中使用汇编语言不难吧,如果要加快程序的运行速度,或者要执行一些以前想都不敢想的实时任务,现在,可以动手试一下了。