- 基本上,我尝试用C模拟汇编代码。**
下面是C代码:
int main()
{
test();
main_next:
printf("Hello, World!");
}
void test()
{
goto main_next;
}
尝试编译此代码(Linux 32位,gcc 4.6.3),我得到了这个错误:
error: label ‘main_randomtag_next’ used but not defined
有谁知道如何在C语言中进行这种过程间跳转吗?
谢谢大家!
4条答案
按热度按时间pvabu6sv1#
但是孩子们怎么办?堆栈?
如果你考虑堆栈,函数之间的
goto
没有任何意义。当你跳转时,堆栈上会有什么?源函数和目标函数可能有不同的参数和不同的返回值。新函数将返回给谁?它的返回值对调用者有意义吗?调用者调用了源函数,而不是目标函数。返回呼叫者?
仔细考虑你的例子:
当
goto
执行时会发生什么?我想你会希望它跳到main()
函数的栈上,goto
实际上和return
一样,调用栈从:但是如果你想跳转到一个不在调用堆栈中的函数,那该怎么办呢?
或替换当前函数?
另一种解释是
goto
会将现有的test()
调用替换为对main()
的一个调用。现在
main()
递归地调用它自己,低位的main()
将返回高位的main()
--顺便说一下,高位的main()
期待一个void
的返回值,但是将接收一个int
。设置jmp和长jmp
最接近的是
setjmp
/longjmp
,它们允许你保存和恢复非本地后藤的堆栈上下文,允许你在函数调用之间跳转。setjmp
和longjmp
通过以下方法解决了我所描述的问题:(a)在跳转时保存和恢复整个堆栈上下文,(b)如果堆栈上下文不再有效,则不允许跳转。setjmp()和longjmp(3)用于处理程序低级子例程中遇到的错误和中断。setjmp()将堆栈上下文/环境保存在env中,以供longjmp(3)稍后使用。如果调用setjmp()的函数返回,则堆栈上下文将无效。
换句话说,
longjmp
在C语言中基本上等同于抛出异常,低级函数可以展开调用堆栈,并在更高级别的函数中继续执行。它的使用也非常棘手,很少是一个好主意。同样,从手册页:
setjmp()和sigsetjmp()使程序难以理解和维护。2如果可能的话,应该使用替代方法。
krcsximq2#
GCC首先生成汇编文件,然后才汇编它,那么使用内联汇编创建标签呢?
然而,这(显然)不应该在真实的情况中使用,因为它根本不考虑堆栈。
qlckcl4x3#
好吧,没有比http://c-faq.com/style/stylewars.html的智慧更好的了!
基本上,如果你只想用C来模拟ASM的行为,那么你应该使用C/C++的所有分支能力。使用函数和函数栈实际上是对goto和标记的改进。正如@ssg明智地所说,这就是结构化编程的全部内容!
bvuwiixz4#
从一个函数跳到另一个函数是不允许的,问题是函数test在堆栈上有一个返回地址,也可能有一个变量的帧,所以为了做到这一点,你应该清除可选的帧,并将堆栈上的地址改为main_next:
所以在这个简单的例子中,你应该直接写而不是后藤main_next return。
但在其他情况下,它会稍微复杂一点,因为你必须明白你想要什么。
main_next之后是否需要代码:就像是在test()中写的一样?你应该提醒这两个函数的局部变量框架是不同的。这意味着如果你只是做一个跳转,那么你将使用main中使用的变量名,但是你将引用test()创建的堆栈框架。这意味着如果两个框架不兼容,那么非常奇怪的事情可能会发生。
问题是你到底想要什么,为什么?
如果你只考虑汇编,并且在堆栈框架中不使用变量,这是可以的,但是没有变量你要做什么呢?
有很多方法可以做你想做的事情,但是你应该决定你到底需要什么,我可以告诉你怎么做!