简单的问题。在C语言中,函数asm
用于在代码中进行内联汇编,但它返回什么?它是否返回传统的eax
,如果不是,它返回什么?
简单的问题。在C语言中,函数asm
用于在代码中进行内联汇编,但它返回什么?它是否返回传统的eax
,如果不是,它返回什么?
__asm__
本身不返回值。C标准没有定义__asm__
如何处理返回值,因此行为可能在编译器之间不同。您说Visual Studio的示例是有效的,但Visual Studio使用__asm
。至少GCC使用__asm__
。
要在C程序中获得结果,您可以将返回值放置在汇编代码中的eax
中,然后从函数返回。调用者将接收eax
的内容作为返回值。即使启用了优化,并且编译器决定内联包含__asm{}
块的函数,也支持这一点。
这可以避免从mov
将值移动到C变量并返回该C变量时,您将从中获取的存储/重新加载,因为MSVC内联asm语法不支持寄存器中的输入/输出(除了这种返回值情况)。
int power2( int num, int power )
{
__asm
{
mov eax, num ; Get first argument
mov ecx, power ; Get second argument
shl eax, cl ; EAX = EAX * ( 2 to the power of CL )
}
// Return with result in EAX
// by falling off the end of a non-void function
}
clang -fasm-blocks
支持相同的内联汇编语法,但不支持从非void
函数末尾掉落并返回asm{}
块在EAX/RAX中留下的值。如果将MSVC内联汇编移植到clang,请注意这一点。当启用优化(函数内联)时,它会严重破坏。
GCC内联汇编HOWTO没有类似的示例。您不能像Visual Studio那样使用隐式返回,但幸运的是,GNU C内联汇编语法允许在寄存器中指定输出。不需要任何技巧来避免存储/重新加载输出值。
HOWTO显示您可以在汇编块中将结果存储到C变量中,并在汇编块结束后返回该变量的值。您甚至可以使用"=r"(var)
让编译器选择其寄存器的选择,在内联之后EAX不是最方便的情况下。
以下是(低效的)字符串复制函数示例,返回dest
的值:
static inline char * strcpy(char * dest,const char *src)
{
int d0, d1, d2;
__asm__ __volatile__( "1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
: "=&S" (d0), "=&D" (d1), "=&a" (d2)
: "0" (src),"1" (dest)
: "memory");
return dest;
}
dest
实际上不是内联汇编语句的输出结果。虚假输出操作数的匹配约束告诉编译器,内联汇编破坏了该变量的副本,因此它需要自己在汇编语句中保留它。)
void
函数中省略了 return
语句,则会收到警告,例如 warning: no return statement in function returning non-void [-Wreturn-type]
,最近的 GCC/clang 甚至不会发出 ret
;它假定这个执行路径永远不会被执行(因为那将是 UB)。无论函数是否包含 asm
语句都无关紧要。__asm { }
块的 -fasm-blocks
支持 不支持 在非 void
函数结尾处掉落,以返回 asm 在 EAX/RAX 中留下的值。只有 MSVC 自身支持(包括内联后)。 - Peter Cordes根据C99规范下的J3实现定义行为,这是不太可能的:
可以使用 asm 关键字将汇编语言直接插入翻译器输出中(6.8)。最常见的实现方式是通过以下形式的语句:
asm ( 字符串文字 );
因此,不太可能有一个实现者会想出一种方法,既将汇编语言插入翻译器输出,又生成一些额外的中间链接代码来将某个寄存器作为返回结果。
它是一个关键字,而不是一个函数。
例如,GCC使用 "=r" 类型的约束语义,允许您在汇编语言中具有对变量的写访问权限。但您需要确保结果最终落在正确的位置。
__asm__()
不是一个函数且没有返回值,因此int i = __asm__()
只是一个无效的语句。 - myaut__asm__();
在 Visual Studio 中都无法正常工作。这是 GCC 语法,在 ICC 和 Clang 上也可以使用,但在 MSVC 上不行。 - Dietrich Epp