返回两次的C函数。(甚至与fork()不太相似)

返回两次的C函数。(甚至与fork()不太相似),c,C,所以我在做一个项目,有点无聊,我想如何真正地打破C: 有可能欺骗编译器对函数调用使用跳转(goto)吗也许,我对自己说。因此,经过一段时间的工作和实践,我意识到一些指针的东西没有正常工作,但是(至少对我来说)以一种意想不到的方式工作:goto无法按预期工作。经过一点实验后,我想到了这个东西(注释被删除了,因为在测试时,我有时会在注释中保留未使用的代码): //作者:我,数组:) #包括 void*func_return(); 无效(*中断ptr)(无效)=(无效*)函数返回; void*func

所以我在做一个项目,有点无聊,我想如何真正地打破C: 有可能欺骗编译器对函数调用使用跳转(goto)吗也许,我对自己说。因此,经过一段时间的工作和实践,我意识到一些指针的东西没有正常工作,但是(至少对我来说)以一种意想不到的方式工作:goto无法按预期工作。经过一点实验后,我想到了这个东西(注释被删除了,因为在测试时,我有时会在注释中保留未使用的代码):

//作者:我,数组:)
#包括
void*func_return();
无效(*中断ptr)(无效)=(无效*)函数返回;
void*func_return(){
printf(“ok2\n”);
break_ptr=&test2;
返回NULL;
如果(0==1){
测试2:
printf(“sh*t\n”);
}
}
无效范围(){
printf(“范围界定的开始”);
break_ptr();
printf(“函数调用后#1\n”);
break_ptr();
printf(!!!您将看不到此!!!!\n”);
}
int main(){
printf(“程序开始\n”);
范围界定();
printf(“结束程序”);
}
我使用gcc来编译它,因为我不知道任何其他编译器支持使用该&&! 我的平台是windows 64位,我使用了最基本的编译方法:

gcc.exe "however_you_want_to_call_it.c" -o "however_you_want_to_call_it.exe"
查看该代码时,我希望它将“sh*t\n”打印到控制台窗口(当然,该窗口将不可见)。但事实证明gcc对我来说有点太聪明了?我猜这是在试图打破某些东西时发生的。。 实际上,正如标题所说,它返回两次:

beginning of programm
beginning of scoping
ok2
after func call #1
ok2
ending programm

它不会返回两次,就像fork函数一样,可能会打印以下内容两次或其他内容,不会从函数和调用它的函数中返回。因此,在第二次调用之后,它不会在控制台上打印“!!!您将不会看到此!!!!\n”,而是“结束程序”,因为它返回了两次。(我试图放大一个事实,“结束程序”是打印出来的,因为程序不会崩溃)

所以,我之所以在这里发表这篇文章,原因如下:我的问题

  • 为什么它不转到/跳转到/调用实际的test2标签,而是转到该函数的开头
  • 我将如何实现我的第一个问题
  • 为什么它会返回两次?我想这可能是一个编译器的东西,而不是运行时的东西,但我想我会等待别人的回答
  • 第一次调用函数“break_ptr”而不是第二次调用时,是否可以实现相同的功能(返回两次)
  • 我不知道,也不关心这是否也在C++中工作。

    现在我看到了很多有用的方法,有些是恶意的,有些实际上是好的。例如,您可以编写一个企业函数,返回您的函数。问题的企业解决方案往往很奇怪,所以为什么不创建一个返回代码idk的函数呢。。 然而,它可能是恶意的,例如,当一些代码意外返回或甚至没有返回值时。。我可以想象,这存在于一个dll文件和一个头文件中,头文件只读取“extern void*break_ptr();”或其他内容。。没有测试它。(然而,还有更残忍的方法可以和某人乱搞……)

    我在互联网上的任何地方都找不到这个文档。请给我一些关于这个的链接或参考资料,如果你找到一些,我想了解更多

    如果这只是一个bug,而gnu/gcc的人正在读这个:请不要删除它,因为处理这些东西太有趣了

    提前感谢您的回答和您的时间,我很抱歉这么长时间。我想确保收集到的关于这件事的一切都在一个地方。(但是,如果我错过了一些东西,我仍然很抱歉。)

    来自gcc文档:

    您不能使用此机制跳转到其他函数中的代码。如果你这样做,完全不可预测的事情就会发生


    您看到的行为已被正确记录。检查生成的程序集以真正了解编译器生成的代码

    大会成员来自:

    显示
    .L2
    标签被放置在函数的顶部,并且编译器优化了
    if(0==1){/*this*/}
    。跳转到
    .L2
    时,跳转到函数的开头,但堆栈设置不正确,因为忽略了
    push rbp

    为什么它不转到/跳转到/调用实际的test2标签,而是转到该函数的开头

    因为文档中说如果你跳转到另一个函数,“完全不可预知的事情会发生”

    我将如何实现我的第一个问题

    很难说,因为“跳入函数”并不是你真正应该做的事情

    为什么它会返回两次?我想这可能是一个编译器的东西,而不是运行时的东西,但我想我会等待别人的回答

    因为返回两次是“不可预知的事情”集合中的一个元素

    第一次调用函数“break_ptr”而不是第二次调用时,是否可以实现相同的功能(返回两次)

    见上文。你所做的会导致不可预知的事情

    我要指出的是,您的代码还存在其他缺陷,这些缺陷可能是其中的一部分,也可能不是其中的一部分
    func_return
    是一个函数,它使用未指定数量的参数返回一个空指针
    break_ptr
    是一个不带参数并返回void的函数。正确的指针应该是

    void * func_return();
    void *(*break_ptr)() = func_return; 
    
    注意三件事。除了删除强制转换外,我还删除了括号中的void并添加了一个星号。但更好的选择是

    void * func_return(void);
    void *(*break_ptr)(void) = func_return; 
    
    这里的主要问题是,不要强制转换以使编译器保持沉默。改为解决问题。了解更多有关铸造的信息

    您的cast调用未定义的行为,这本质上与“不可预知的事情发生”相同

    另外,该函数中缺少一个return语句

    void * func_return(){
        printf("ok2\n");
        break_ptr = &&test2;
        return NULL;
        if(0 == 1){
          test2:
          printf("sh*t\n");
        }
        // What happens here?
    }
    
    void * func_return(){
        printf("ok2\n");
        break_ptr = &&test2;
        return NULL;
        if(0 == 1){
          test2:
          printf("sh*t\n");
        }
        // What happens here?
    }