如何“转到”c中的不同function?

基本上我试图在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中进行这种程序间的转换?

谢谢!

但那些孩子呢? 堆?

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

回到来电者?

仔细考虑你的例子:

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

goto执行时会发生什么? 我认为你希望这会将堆栈跳回到调用main()函数。 goto实际上与return相同,从而改变调用堆栈:

 main() main() | to +--> test() 

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

或者更换当前function?

一种不同的解释是goto将用main()替换现有的test()调用。 调用堆栈将从以下更改:

 main() main() | to | +--> test() +--> main() 

现在main()递归调用自身,而较低的main()将返回上部main() -who,顺便说一下,期望一个void返回值但是将接收一个int

setjmp和longjmp

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

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

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

换句话说, longjmp基本上就是抛出exception的C等价物。 低级函数可以展开调用堆栈并在更高级别的函数中恢复执行。

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

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

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

 void test() { __asm__ volatile ( "jmp main_next" ); } int main() { test(); __asm__ volatile ( "main_next:" ); printf("hello, world"); } 

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

好吧,说不出比http://c-faq.com/style/stylewars.html的智慧更好!

基本上,如果您只想使用C模拟ASM的行为,那么您应该实际使用C / C ++的所有分支function。 使用函数和函数堆栈实际上是对gotos和tags的改进。 正如@ssg明智地说的那样,这就是结构化编程的全部内容!

不允许从另一个函数内跳转。 问题是函数“test”在堆栈上有一个返回地址,也许是变量的框架。 所以为了做到这一点,你应该清理可选框架并使用main_next的地址更改堆栈上的地址:

所以在这个基本的例子中,你应该只写而不是转到main_next返回。

但在其他情况下,它有点复杂,因为你必须了解你想要的东西。

你需要在main_next之后得到代码:好像它是用test()编写的吗? 您应该提醒这两个函数的局部变量帧是不同的。 这意味着如果你只是跳转,那么你将使用main中使用的变量的名称,但是你将引用test()创建的堆栈帧。 这意味着如果两个帧不兼容,那么可能会发生非常奇怪的事情。

问题是你想要什么,为什么?

如果你考虑只是汇编,并且你不在堆栈帧中使用变量,那就没问题。 但是如果没有变量你会怎么做?

有办法做你想做的事,但你应该决定你需要什么,我可以告诉你如何做到这一点!