AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > VC编程

在Visual C++中使用内联汇编

51自学网 2015-08-30 http://www.wanshiok.com

  四、在__asm块中使用C/C++语言元素

  C/C++与汇编可以混合使用,在内联汇编可以使用C/C++的变量和很多其它C/C++的元素。在__asm块中可以使用以下C/C++元素:

  1.符号,包括标号、变量和函数名;

  2.常量,包括符号常量和枚举型(enum)成员;

  3.宏定义和预处理指示符;

  4.注释,包括"/**/"和"//";

  5.类型名,包括所有MASM中合法的类型

  6.typedef名称, 像PTR、TYPE、特定的结构成员或枚举成员这样的通用操作符。

  在__asm块中,可以使用C/C++或ASM的基数计数法(比如: 0x100和100H是相等的)。

  __asm块中不能使用像<<一类的C/C++操作符。C/C++和MASM通用的操作符,比如"*"和"[]"操作符,都被认为是汇编语言的操作符。举个例子:

int array[10];

__asm MOV array[6], BX ; Store BX at array+6 (not scaled)

array[6] = 0; /* Store 0 at array+12 (scaled) */

  * 小技巧: 内联汇编中,你可以使用TYPE操作符使作其与C一致。比如,下面两条语句是一样的:

__asm MOV array[6 * TYPE int], 0 ; Store 0 at array + 12

array[6] = 0; /* Store 0 at array + 12 */

  内联汇编能通过变两名直接引用C/C++的变量。__asm块中可以引用任何符号,包括变量名。

  如果C/C++中的类、结构或者枚举成员具有唯一的名称,如果在"."操作符之前不指定变量或者typedef名称,则__asm块中只能引用成员名称。然而,如果成员不是唯一的,你必须在"."操作符之前加上变量名或typedef名称。例如,下面的两个结构都具有same_name这个成员变量:

struct first_type
{
char *weasel;
int same_name;
};

struct second_type
{
int wonton;
long same_name;
};

  如果按下面声明变量:

struct first_type hal;
struct second_type oat;

  那么,所有引用same_name成员的地方都必须使用变量名,因为same_name不是唯一的。另外,上面的weasel变量具有唯一的名称,你可以仅仅使用它的成员名称来引用它:

__asm
{
MOV EBX, OFFSET hal
MOV ECX, [EBX]hal.same_name ; 必须使用 'hal'
MOV ESI, [EBX].weasel ; 可以省略 'hal'
}

  注意,省略了变量名仅仅是为了写代码的方便,生成的汇编指令的还是一样的。

  可以不受限制地访问C++成员变量,但是不能调用C++的成员函数。

  五、寄存器使用

  一般来说,在__asm块开始的时候,寄存器是空的,不能在两个__asm之间保存寄存器的值。(这是MSDN上说的,我在实际使用时发现,好像并不是这样。不过它是说"一般",我是特殊:))

  如果一个函数被声明成了__fastcall,则其参数将放在寄存器中,这将给寄存器的管理带来问题。所以,如果要将一个函数声明成__fastcall,必须保存ECX寄存器。为了避免以上的冲突,在声明为__fastcall的函数中不要有__asm块。如果用了/Gr编译选项(它全局的变成__fastcall),将每个函数声明成__cdecl或者__stdcall,这个属性告诉编译器用传统的C方法。

  如果使用EAX、EBX、ECX、EDX、ESI和EDI寄存器,你不需要保存它;但如果你用到了DS、 SS、SP、BP和标志寄存器,那就应该PUSH保存这些寄存器。

  如果程序中改变了用于STD和CLD的方向标志,你必须将其恢复到原来的值。

  六、转跳

  可以在C里面使用goto调到__asm块中的标号处,也可以在__asm块中转跳到__asm块里面和外面的标号处。__asm块内的标号是不区分大小写的(指令、指示符等也是不区分大小写的)。例:

void func()
{
goto C_Dest; /* 合法 */
goto c_dest; /* 错误 */

goto A_Dest; /* 合法 */
goto a_dest; /* 合法 */

__asm
{
JMP C_Dest ; 合法
JMP c_dest ; MSDN上说合法,但是我在VS.NET中编译,认为这样不合法

JMP A_Dest ; 合法
JMP a_dest ; 合法

a_dest: ; __asm 标号
}

C_Dest: /* C的标号 */
return;
}

  不要使用函数名称当作标号,否则将使其跳到函数执行而不是标号处。如下所示:

; 错误: 使用函数名作为标号
JNE exit
.
.
.
exit:
; 下面是更多的ASM代码

  美元符号$用于指定当前位置,如下所用,常用于条件跳转:

JNE $+5 ; 下面这条指令的长度是5个字节
JMP farlabel
;$+5,跳到了这里
.
.
.
farlabel:

 
 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。

上一篇:托盘编程全接触  下一篇:理解&nbsp;Visual&nbsp;C++&nbsp;Extensions&nbsp;for&nbsp;ADO