禁用C语言中的return关键字

3

我想知道是否有一种好的方法可以在C函数中禁用返回。

虽然我通常不会这样做,但有些情况下,在特定的代码块中不应该返回,我想确保这一点。

通常这是为了确保清理函数运行或状态没有留下无效的情况。

如果有许多人在编写代码,那么一些编译器检查可能很方便,因为这可能会意外地漏掉。

 some_function(void)
 {
     /* ... code ... */

 #define return __noreturn__  /* any unknown identifier */
     { int return; (void)return; }  /* avoids gcc's '-Wunused-macros' */

     /* ... code which _can't_ return ... */

 #undef return

     /* ... code which _can_ return ... */

 }

这个方法虽然可行,但比较丑陋,我不想在除了快速本地测试之外的任何场景中使用它。

有没有一种设置宏来禁用和重新启用返回的方式?(也许可以使用某些有毒的_Pragma?但它必须能够解毒)。

 some_function(void)
 {
     /* ... code ... */
     RETURN_DISABLE;
     /* ... code which _can't_ return ... */
     RETURN_ENABLE;
     /* ... code which _can_ return ... */

 }

注意 1)我知道在大多数情况下,有更好的解决方案,这涉及到重构代码,但我认为仍有一些情况下这种保证是有用的。

注意 2)使用goto仍然可以绕过清理代码,但我认为这种情况超出了本问题的范围。


只需在本地快速测试中搜索“return”即可。如果您可以将返回值存储在变量中,并自律地始终返回该变量,则如果它与您拥有的块一起工作,则始终可以延迟定义该变量,直到不能返回的代码之后。 - Crowman
是的,大多数情况下这已经足够好了。尽管在宏中进行本地搜索return无法找到return(我上面链接的示例可以)。但是,在宏中返回是我尽量避免的事情。 - ideasman42
@Paul Griffiths,没错,但这意味着在所有开发人员提交更改之前都必须设置额外的工具。如果可以使用预处理器(甚至是编译器扩展)来完成此操作,我更愿意走这条路。但我不认为这是偏执狂,根据我的经验,由于从函数返回、忘记释放资源而导致的错误非常普遍,虽然这不能解决这个问题,但在某些情况下它至少可以减轻一些问题。 - ideasman42
5
“large complex functions should not return within specific blocks of code...” 这句话让我想到了 XY 问题。更好的解决方法可能是使用更好分解的函数、静态分析和谨慎地使用 goto,而不是在特定的代码块中返回。 - Brian Cain
1
我怀疑你无法在语言内解决这个问题。我建议:考虑使用clang分析器,考虑编写一个pass来解决这个问题。(即:在clang中创建一个函数属性,每当clang分析器发现此属性时启动您的分析pass) - Alexander Oh
显示剩余3条评论
1个回答

3
您正在尝试解决一个编译器问题,这个问题应该通过代码审查和编码规范来解决。
一个好的经验法则是函数不应该有多个退出点。这使得它们更难理解,也更难确保清理代码运行(您在此遇到的问题)。如果函数太大,以至于您认为可能会错过返回语句,那么它可能需要拆分成较小的函数。
例如,您可以拥有:
int some_func(...)
{
      init_some_func(...);
      err = some_func_work(...)
      clean_up_some_func(...);
      return err;
}

或类似的东西。现在,从工作函数返回将始终导致清理工作的完成。

您可以通过代码审查和标准来检查未初始化变量的使用情况,但自动化检查也是有用的(因此使用“-Wuninitialized”选项),但您是正确的 - 在大多数情况下最好将函数拆分出来。 - ideasman42
@ideasman42:我肯定会使用-Wall和-Werror编译,并充分利用编译器的优势。但是编译器无法知道您想要运行一些清理代码的部分。这是一个逻辑错误。为此,您将需要使用其他方法。此外,您如何确保已在正确位置设置了DISABLE_RETURN()! - dave
1
你假设我试图让编译器替我思考,当然编译器不可能知道,但是我知道,我想向编译器指示这一点。如果代码中的注释可以得到警告的支持,我可以添加一些注释,我认为这是一个优势。同样,我可以在函数上添加注释,说明它的返回值应该始终被使用,或者使用__attribute__((warn_unused_result))属性。 - ideasman42

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接