仅一次评估宏参数

Mat*_*ner 5 c macros gcc c-preprocessor

在下面的代码中,传递retval给as的任何值都将按每次使用该令牌的方式评估。

#define _CPFS_RETURN(commit, retval) do { \
        util_cpfs_exit(commit); \
        return retval; \
    } while (false)

#define CPFS_RETURN_BOOL(retval) do { \
        _CPFS_RETURN(retval, retval); \
    } while (false)
Run Code Online (Sandbox Code Playgroud)

例如给定use CPFS_RETURN_BOOL(inode && file_truncate(inode, len));,将生成:

do { 
    do {
        util_cpfs_exit(inode && file_truncate(inode, len));
        return inode && file_truncate(inode, len);
    } while (0);
} while (0);
Run Code Online (Sandbox Code Playgroud)

显然,我不想inode && file_truncate(inode, len);多次执行该语句。我如何确保在粘贴helter-skelter之前评估给定的令牌?

更新资料

我相信我有充分的理由在这里使用宏。在可能的情况下,将代码放入实际函数(例如util_cpfs_exit)中,这些函数从我正在使用的一组宏中调用。宏根据返回类型的不同而有所不同:在C ++中,我将使用显式模板来处理此问题。

kri*_*iss 3

由于宏的返回类型不同,您可以计算 retval 表达式并将其存储在宏第一级内正确类型的变量中,然后使用该变量。IE:

#define CPFS_RETURN_BOOL(retval) do { \
    bool _tmp_ = retval;
    _CPFS_RETURN(_tmp_, _tmp_); \
} while (false);
Run Code Online (Sandbox Code Playgroud)

如果我理解得很好,这对于您的用例来说应该足够了,对于其他用例,您可以使用函数。

在你的例子中你会得到:

do {
   bool _tmp_ = inode && file_truncate(inode, len);
   do {
      util_cpfs_exit(_tmp_);
      return _tmp_;
   } while (0);
} while (0);
Run Code Online (Sandbox Code Playgroud)

看起来不错。

PS:作为旁注,如果您始终通过遵循上述模型的另一个宏间接使用 _CPFS_RETURN,则无需通过do { } while (false);. 另外,在 the 之后放置一个分号while(false)会消除使用它的大部分兴趣...这可能是为什么 C 宏是危险的并且隐藏了容易的陷阱的一个很好的例子。并不是说我不喜欢宏,恰恰相反。我来自这样一种人(可能很少见),他们希望 C 宏得到增强,以绕过其当前的限制,变得非常酷(不,C++ 模板不是增强型宏,它们是完全不同的东西)。