仅评估一次宏参数

在下面的代码中,任何传递为retval被评估为每次使用该令牌时给出的内容。

 #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) 

例如,给定使用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); 

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

更新

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

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

 #define CPFS_RETURN_BOOL(retval) do { \ bool _tmp_ = retval; _CPFS_RETURN(_tmp_, _tmp_); \ } while (false); 

如果我理解得很好,那对你的用例就足够了,对于其他用例,你可以使用函数。

在你的例子中你会得到:

 do { bool _tmp_ = inode && file_truncate(inode, len); do { util_cpfs_exit(_tmp_); return _tmp_; } while (0); } while (0); 

看起来很好。

PS:作为旁注,如果你总是在上述模型之后通过另一个宏间接使用_CPFS_RETURN,则不需要通过do { } while (false);来保护它do { } while (false); 。 此外,在while(false)之后放置一个分号消除了使用它的大部分兴趣……这可能是为什么C宏是危险的并隐藏容易陷阱的一个很好的例子。 不是说我不喜欢宏,恰恰相反。 我来自(可能是罕见的)那些希望增强C宏来绕过当前限制而变得非常酷的人(不,C ++模板不是增强型宏,它们是完全不同的东西)。

编写函数而不是使用宏。 在这种情况下,如果要构建一个return语句,最好只显式编写代码,而不是依赖宏来隐藏你正在做的事情。

我建议你先评估病情。

 bool val = inode && file_truncate(inode, len); 

除此之外,可能建议避免使用宏,在这种情况下它们似乎是不必要的,而是使用函数。

将宏更改为“静态内联”function。 在gcc中,它和宏一样快。 http://gcc.gnu.org/onlinedocs/gcc/Inline.html