如何"转到"c中的不同功能?

lll*_*lll 23 c assembly calling-convention

基本上我试图在C中模拟汇编代码.

这是C代码:

int main()
{
   test();
main_next:
   printf("Hello, World!");
}

void test()
{
     goto main_next;
}
Run Code Online (Sandbox Code Playgroud)

尝试编译此代码(Linux 32位,gcc 4.6.3),我收到此错误:

 error: label ‘main_randomtag_next’ used but not defined
Run Code Online (Sandbox Code Playgroud)

有谁知道如何在C中进行这种程序间的转换?

谢谢!

Joh*_*ica 33

但那些孩子呢?堆?

goto如果你考虑堆栈,函数之间没有任何意义.跳跃时会在堆叠中出现什么?源和目标函数可能具有不同的参数和不同的返回值.新功能将返回谁?它的返回值是否对调用者有意义?调用者调用源函数,而不是目标函数.

回到来电者?

仔细考虑你的例子:

int main()
{
   test();
main_next:
   printf("hello, world);
}

void test()
{
     goto main_next;
}
Run Code Online (Sandbox Code Playgroud)

goto执行时会发生什么?我认为你希望这会将堆栈跳回到调用main()函数.该goto会有效地相同的return,从改变调用堆栈:

main()                            main()
|                   to            
+--> test()                       
Run Code Online (Sandbox Code Playgroud)

但是如果你想跳转到不在调用堆栈中的函数呢?然后怎样呢?

或者更换当前功能?

另一种解释是,用一个goto替换现有的test()呼叫main().调用堆栈将改为:

main()                            main()
|                   to            |
+--> test()                       +--> main()
Run Code Online (Sandbox Code Playgroud)

现在main()是递归调用自己,并且较低的main()将返回到upper main()-who,顺便说一下,期望void返回值但是将接收到int.

setjmp和longjmp

你最接近的是setjmp/ longjmp.这些允许您保存和恢复非本地goto的堆栈上下文,允许您在函数调用之间跳转.

setjmplongjmp解决我所描述的问题:(a)跳转时保存和恢复完整的堆栈上下文,以及(b)如果堆栈上下文不再有效则不允许跳转.我引用了手册页(强调我的):

setjmp()和longjmp(3)对于处理程序的低级子例程中遇到的错误和中断很有用.setjmp()将堆栈上下文/环境保存在env中,供以后使用longjmp(3).如果调用setjmp()的函数返回,则堆栈上下文将无效.

换句话说,longjmp基本上是C等同于抛出异常.低级函数可以展开调用堆栈并在更高级别的函数中恢复执行.

使用它也非常棘手,很少有好主意.再次,从手册页:

setjmp()和sigsetjmp()使程序难以理解和维护.如果可能,应使用替代方案.

  • 谢谢你的出色答案约翰:)我学到了很多东西!最后,我选择了一个快速的解决方案,将文本部分中的所有代码放在一个函数中,从而绕过了问题.... (2认同)

Max*_*ysh 6

GCC首先生成汇编文件,然后才汇编它,那么使用内联汇编创建标签呢?

void test()
{
    __asm__ volatile ( 
         "jmp main_next"
    );
}


int main()
{
    test();
    __asm__ volatile ( 
        "main_next:"
    );
    printf("hello, world");
}
Run Code Online (Sandbox Code Playgroud)

但是,这(显然)不应该在实际情况下使用,因为它根本不处理堆栈.

  • 这只是创建非工作程序的众多方法之一,通过使用内联asm来执行编译器期望它*不*执行的操作.您可以使用[`ASM goto`(https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#GotoLabels)告诉编译器在您的ASM可以跳,但仅限于在当前函数约翰的答案解释了同样的原因. (3认同)