【问题标题】:Get return type of function in macro (C++)获取宏中函数的返回类型(C++)
【发布时间】:2012-01-29 19:19:16
【问题描述】:

我有ASSERT(x) 宏,如果它断言(在发布配置中),我想调用return。 为此,我需要知道我在其中使用ASSERT 的函数的返回类型。如何获取(我处理C++03LLVM GCC 4.2编译器)?

我的 ASSERT 宏:

#define ASSERT(x) \
    if(!(x)) {
        LOG ("ASSERT in %s: %d", __FILE__, __LINE__); \
        return /*return_type()*/; \
    }

PS:我试过 return 0; - 编译器显示 void 函数错误(我没有尝试复杂返回类型),如果 return; - 非 void 函数错误。

(已更新...)

我会在这里回答 werewindlenyarlathotepjdv-Jan de Vaan。我使用标准assert 进行调试配置。但经过 beta 测试后,我仍然会收到最终客户的崩溃报告,而且在大多数情况下,我需要更改我的崩溃函数:

ASSERT (_some_condition_);
if (!_some_condition_)      // add this return
    return _default_value_;

我明白,我的程序可能稍后会崩溃(否则它肯定会在当前函数中崩溃)。我也不能退出应用程序,因为开发是为 iPhone 开发的(应用程序可能不会在那里以编程方式退出)。所以最简单的方法是在断言失败时“自动返回”。

【问题讨论】:

  • 当他们说应用程序不能以编程方式退出时,他们并不意味着无论您的程序有什么错误,您都应该继续运行。他们的意思是说您的应用在提交之前应该没有错误
  • iPhone - 那不是 Objective-C 而不是 C++?
  • 你有没有想过使用异常?似乎您可以有一个非常高级的 try-catch 块,然后记录您可以合并到异常对象中的消息(以及__FILE____LINE__ 给出的位置)。您似乎对返回值根本不感兴趣,是吗?

标签: c++ function types assert


【解决方案1】:

我相信您正在尝试解决错误的问题。你不希望你的程序在断言的情况下崩溃,你最好改进你的测试。

在这些断言中使用“return”会给您一种错误的安全感。相反,它隐藏了您的问题并导致程序中出现意外行为,因此您遇到的错误要复杂得多。我的一个同事实际上写了一篇很好的blog post

如果您真的想要它,您可以尝试编写 return {}; 以便它默认构造值,或者在您还提供失败案例的地方使用断言宏。不过我真的不推荐!

【讨论】:

    【解决方案2】:

    就这样做

    #define ASSERT(x, ret, type)    \
         if(!(x)){
              LOG ("ASSERT in %s: %d", __FILE__, __LINE__); \
              return (type) ret;
         }
    

    【讨论】:

    • 如果用户提供ret,则不需要提供类型。
    【解决方案3】:

    你不能这样做,C/C++ 预处理器非常基础,它不能进行任何代码分析。您最多可以将返回类型传递给宏。

    但这是我的观点:您以错误的方式使用断言。它们应该只用于代码的健全性检查(对于错误只能因为程序员而发生);如果所有断言都通过了,你就不需要关心它们,你不需要记录它们。

    不仅如此,而且(通常)你应该使用最不意外的元素。您是否期望ASSERT 记录一些内容然后强制使函数返回?我知道我不会。我要么期望它完全关闭应用程序(标准 assert 所做的),要么让我决定接下来会发生什么(也许我有一些免费的指针)。

    【讨论】:

      【解决方案4】:

      您可以根据需要定义另一个宏。

      #define ASSERT(x) \
          if(!(x)) { \
              LOG ("ASSERT in %s: %d", __FILE__, __LINE__); \
              ASSERT_DEFAULT_RETURN(); \
          }
      

      然后在函数内部:

      int foo(){
      #ifdef ASSERT_DEFAULT_RETURN
      #undef ASSERT_DEFAULT_RETURN
      #endif
      #define ASSERT_DEFAULT_RETURN() return 0
        // ...
        ASSERT(some_expression);
        // ...
        // cleanup
      #undef ASSERT_DEFAULT_RETURN
      }
      

      【讨论】:

      • 这还不够“精致”,但可能是一个解决方案。使用最少的编码,它看起来像ASSERT(condition, return_command),使用它:ASSERT (x, return 0);
      【解决方案5】:

      您无法确定宏中周围函数的返回类型;宏由预处理器扩展,它没有关于这些宏出现的环境的这种信息;它基本上只是“搜索和替换”宏。您必须为每种返回类型编写单独的宏。

      但为什么不退出程序(即调用exit 函数)?仅仅从函数返回似乎不是一个非常健壮的错误处理。毕竟,失败的断言应该只在出现严重错误时才会发生(意味着程序处于它无法处理的状态),因此最好退出program as soon as possible

      【讨论】:

      • 如果编译器供应商愿意,他当然可以添加这样的宏。它与 LINEFUNC 等没有什么不同。
      • 返回某些东西的一个原因是静态分析工具可以查看所有可能的流程。如果他们遇到回报 - 他们知道流程已经结束。如果他们遇到出口 - 他们不会。
      【解决方案6】:

      我认为您可以使用模板函数来执行此操作,您可以从宏中调用 default(x)。

      template<class T> default<T>(T x) { return T(); }
      

      这将适用于所有使用默认构造函数的情况。我认为您需要为 void 编写一个特殊的宏。

      我希望我的模板语法正确,我的 c++ 越来越生锈了。

      【讨论】:

      • 什么参数传递给default()
      • 返回值。它将返回类型 T 的默认值,这是无参数 ctor 产生的值。
      【解决方案7】:

      在 C 中没有正确的方法来确定函数内部的返回类型。

      此外,如果您以某种方式实现ASSERT 的变体,则会导致错误的程序行为。 ASSERT 的主要思想:如果失败,则程序处于未定义状态,唯一正确的方法是立即停止它。 IE。致电exit()

      【讨论】:

        【解决方案8】:

        宏没有return 值,因为它们本身不是函数。它们替换了使用它们的源代码,因此您可以在使用宏的函数中使用return

        无法从宏中获取return value

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-07-01
          • 2018-11-06
          • 1970-01-01
          • 2015-09-14
          • 1970-01-01
          • 2016-06-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多