C++ 将引用参数传递给汇编函数

C++ 将引用参数传递给汇编函数,c++,assembly,x86,C++,Assembly,X86,我有一个包含3个引用参数的函数,其中包含一些汇编代码。 我想得到变量R,G,B中函数的结果,如下所示 void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) { _asm { push EAX; xor EAX, EAX; mov EAX,color; mov R, AL;

我有一个包含3个引用参数的函数,其中包含一些汇编代码。 我想得到变量R,G,B中函数的结果,如下所示

     void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B)     {

    _asm {
        push EAX;
        xor EAX, EAX;
        mov EAX,color;
        mov R, AL;
        mov G, AH;
        shr EAX, 16;
        mov B, AL;
        pop EAX;
    }
  }
例如,我使用函数作为

DWORD  color=RGB(76,0,0);
uint8_t R,   G, B;
Get_RGB_color(color , R ,G ,B );
这些代码有两个问题:

1-在EAX中获取错误值 mov-EAX,颜色

2-行中出现错误“操作数大小冲突”

mov-R,AL; mov G,啊,; mov-B,AL

请帮帮我

你为什么把EAX推到这里?没有必要这样做。EAX是一个调用者保存寄存器,这意味着被调用者(即,您的函数)可以自由地对其进行删除。您无需保留其价值。
(EAX、EDX和ECX是Win32 ABI中的调用方保存寄存器;其他是调用方保存寄存器。)

推送寄存器的唯一其他原因是对齐堆栈,但这在这里也不是必需的。当控件传递给函数时,堆栈将已正确对齐

我想您知道这是清除寄存器的常用技巧(用自身进行XORing)。但是,在将值移动到寄存器中之前,不需要预先清除寄存器

这条线错了;这就是汇编程序错误告诉你的
color
作为对DWORD的引用传递给此函数,但在引擎盖下,引用作为指针实现,因此它实际上作为指向DWORD的指针传递。这意味着您不能直接访问color的值,必须使用指针间接寻址(或x86术语)。由于您使用的是内联汇编,因此可以让编译器为您进行堆栈簿记,只需通过形式参数的名称引用内存位置:

mov EAX, DWORD PTR [color]   ; get the address of color
mov EAX, DWORD PTR [EAX]     ; dereference it, storing the result in EAX
当然,由于您实际上没有在该函数内部修改
颜色
,因此没有理由将其作为参考参数传递。通常,标量值(例如整数)应始终通过值传递,而不是通过引用传递,除非您实际需要引用。优化编译器将在寄存器中传递值,这使得指针间接寻址及其伴随的开销完全不必要,因此效率更高,可读性更强。

这里,汇编器给您一个“操作数大小冲突”错误。因为
R
实际上是一个引用,作为指针实现,所以它是32位的。它是指向内存中8位位置的32位指针。因此,您试图将8位值(AL)移动到32位位置(指针)。操作数的大小不同。所以再一次,你必须使用间接寻址。它看起来就像上面的代码,只是现在
R
是字节大小的,您需要使用不同的寄存器作为暂存寄存器,以避免重击EAX中的值,我们为此付出了巨大努力:

mov EDX, DWORD PTR [R]    ; get the address of R
mov BYTE PTR [EDX], AL    ; dereference it so we can store AL in there
这将EAX的低位字节(我们可以称之为AL)移动到
R
指定的字节大小的内存位置

下一行也是一样,只是现在您正在移动EAX的高位字节(称为AH)。我们现在可以在这里重用EDX,因为我们不再需要它的旧值:

mov EDX, DWORD PTR [G]    ; get the address of G
mov BYTE PTR [EDX], AH    ; dereference it so we can store AH in there
这是正确的

第三节,和第一节一样。如您所知,这应该是:

mov EDX, DWORD PTR [B]    ; get the address of B
mov BYTE PTR [EDX], AL    ; dereference it so we can store AL in there
弹出EAX现在是不必要的,因为我们在开始时没有推动EAX


然后,将所有这些放在一起,您将得到以下一系列说明:

void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{
    __asm
    {
        mov  EAX, DWORD PTR [color]
        mov  EAX, DWORD PTR [EAX]

        mov  EDX, DWORD PTR [R]
        mov  BYTE PTR [EDX], AL

        mov  EDX, DWORD PTR [G]
        mov  BYTE PTR [EDX], AH

        shr  EAX, 16
        mov  EDX, DWORD PTR [B]
        mov  BYTE PTR [EDX], AL
    }
}
然而,这并不是编写代码的最佳方式。访问32位寄存器的低8位和高8位虽然是允许的,但速度较慢。优化编译器可以避免这种情况,并且在此过程中,可以避免使用移位指令:

void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{
    __asm
    {
        mov  EAX, DWORD PTR [color]   ; get the address of color
        mov  EAX, DWORD PTR [EAX]     ; get the value in EAX

        mov  EDX, DWORD PTR [R]       ; get the address of R
        mov  CL,  BYTE PTR [EAX]      ; get the value of the lowest byte (8 bits) of color
        mov  BYTE PTR [EDX], CL       ; dereference R and store that byte in it

        mov  EDX, DWORD PTR [G]       ; get the address of G
        mov  CL, BYTE PTR [EAX + 1]   ; get the value of the second-to-lowest byte in color
        mov  BYTE PTR [EDX], CL       ; dereference G and store that byte in it

        mov  EDX, DWORD PTR [B]       ; get the address of B
        mov  CL, BYTE PTR [EAX + 2]   ; get the value of the third-to-lowest byte in color
        mov  BYTE PTR [EDX], CL       ; dereference B and store that byte in it
    }
}
但仍有部分登记摊位潜伏在那里,以减缓事态的发展。因此,一个真正聪明的编译器可以通过预调零寄存器或使用
movzx
来消除这些错误:

void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{
    __asm
    {
            mov    EAX, DWORD PTR [color]
            mov    EAX, DWORD PTR [EAX]

            mov    EDX, DWORD PTR [R]
            movzx  ECX, BYTE PTR [EAX]
            mov    BYTE PTR [EDX], CL

            mov    EDX, DWORD PTR [G]
            movzx  ECX, BYTE PTR [EAX + 1]
            mov    BYTE PTR [EDX], CL

            mov    EDX, DWORD PTR [B]
            movzx  ECX, BYTE PTR [EAX + 2]
            mov    BYTE PTR [EDX], CL
    }
}
它还可以对指令进行重新排序,并巧妙地分配寄存器以尽可能地并行这三个操作。毫无疑问,还有更有效的方法可以做到这一点。除非您试图学习汇编语言编程(在这种情况下,使用内联汇编程序没有多大意义),否则强烈希望编写如下代码:

void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{
    R = (color & 0xFF);
    G = ((color >>  8) & 0xFF);
    B = ((color >> 16) & 0xFF);
}

最后一点注意:即使在使用内联汇编语法时,也不需要以分号结束每个汇编语言指令。这只是C和C++中的必要条件。不过,这并不重要,因为分号实际上是汇编程序中的注释分隔符,所以它类似于在C中编写以下代码:

int foo;/**/

引用实际上是作为指针传递的,您需要这样对待它们。PS:没有理由使用汇编。我想我可以得到变量的地址,如何才能得到变量的值?我要强调Jester已经说过的话。你认为这个程序集会比编译器生成的代码快吗?我认为程序集代码是获得结果的较短方式,速度对这个主题并不重要。在这种情况下,在程序集中编写代码既不短也不快。使用这样的简单代码,编译器可以做得更好。说到更快和更短,您最好通过值传递像
color
这样的简单标量类型,而不是通过引用。这样,这个值可以简单地登记在一个寄存器中。谢谢你的帮助。@赛义德7:如果这个答案帮助你解决了你的问题,那么你应该考虑接受答案。更多接受答案的方式和原因可在此处找到:。我还注意到你从未接受过任何对你有用的答案。你看起来是新来的,我建议你回顾一下你的其他问题,接受任何能解决你问题的答案。欢迎来到Stackoverflow!
mov EDX, DWORD PTR [B]    ; get the address of B
mov BYTE PTR [EDX], AL    ; dereference it so we can store AL in there
pop EAX;
void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{
    __asm
    {
        mov  EAX, DWORD PTR [color]
        mov  EAX, DWORD PTR [EAX]

        mov  EDX, DWORD PTR [R]
        mov  BYTE PTR [EDX], AL

        mov  EDX, DWORD PTR [G]
        mov  BYTE PTR [EDX], AH

        shr  EAX, 16
        mov  EDX, DWORD PTR [B]
        mov  BYTE PTR [EDX], AL
    }
}
void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{
    __asm
    {
        mov  EAX, DWORD PTR [color]   ; get the address of color
        mov  EAX, DWORD PTR [EAX]     ; get the value in EAX

        mov  EDX, DWORD PTR [R]       ; get the address of R
        mov  CL,  BYTE PTR [EAX]      ; get the value of the lowest byte (8 bits) of color
        mov  BYTE PTR [EDX], CL       ; dereference R and store that byte in it

        mov  EDX, DWORD PTR [G]       ; get the address of G
        mov  CL, BYTE PTR [EAX + 1]   ; get the value of the second-to-lowest byte in color
        mov  BYTE PTR [EDX], CL       ; dereference G and store that byte in it

        mov  EDX, DWORD PTR [B]       ; get the address of B
        mov  CL, BYTE PTR [EAX + 2]   ; get the value of the third-to-lowest byte in color
        mov  BYTE PTR [EDX], CL       ; dereference B and store that byte in it
    }
}
void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{
    __asm
    {
            mov    EAX, DWORD PTR [color]
            mov    EAX, DWORD PTR [EAX]

            mov    EDX, DWORD PTR [R]
            movzx  ECX, BYTE PTR [EAX]
            mov    BYTE PTR [EDX], CL

            mov    EDX, DWORD PTR [G]
            movzx  ECX, BYTE PTR [EAX + 1]
            mov    BYTE PTR [EDX], CL

            mov    EDX, DWORD PTR [B]
            movzx  ECX, BYTE PTR [EAX + 2]
            mov    BYTE PTR [EDX], CL
    }
}
void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{
    R = (color & 0xFF);
    G = ((color >>  8) & 0xFF);
    B = ((color >> 16) & 0xFF);
}
int foo;/**/