在括号中包装 goto 标签 跳过宏来自下面的评论

问题描述

所以我有一个像这样的 marco 函数

#define PROPOGATE_METHOD(status,function,propogationMethod) \
     status = function; \
     if(status != eSuccess)\
     {\
        propogationMethod; \
     }

所以就像任何优秀的开发人员都会做的那样,我想将每个参数包装成这样:

#define PROPOGATE_METHOD(status,propogationMethod) \
     (status) = (function); \
     if((status) != eSuccess)\
     {\
        (propogationMethod); \
     }

但是如果我用 goto 或 return 调用这个宏函数,我会得到一个错误(在 goto 之前期望表达式)。 i.e. PROPOGATE_METHOD(status,functionCall(),goto Error;);

关于解决这个问题的想法?我正在考虑将 goto 移动到宏函数中,并环绕标签,但这会引发另一个错误expected identifier or ‘*’ before ‘(’ token

解决方法

所以就像任何优秀的开发人员都会做的那样,我想将每个参数都包装成这样

@StoryTeller 在评论部分对此做出了很好的回应。 “优秀的开发人员了解建议存在的原因,它解决了什么问题,最重要的是,当它不适用时。盲目地做某事不是好的开发。”

另一个适用的引用是“盲目遵循最佳实践不是最佳实践”

在这里,您似乎真的要添加括号,因为有人说“在参数周围加上括号是件好事”。不是因为在这种特殊情况下有任何有效的目的。

跳过宏

我真的不明白这个宏的目的。 TBH,看起来你在炫耀,但是像这样的宏很可能会导致难以追踪的错误。如果只是为了节省一些行,你实际上可以在没有任何宏的情况下制作一个有点像样的单行。

if((status = foo()) != eSuccess) goto Error;

if((status = foo()) != eSuccess) return x;

if((status = foo()) != eSuccess) bar();

在许多情况下,我更喜欢在两行或三行上制作它们。但以上情况并没有那么糟糕。我肯定会说它比宏更好。请记住 status = foo() 周围的额外括号。如果忘记这是一个大问题,你可以这样做:

int foo_wrapper(int *status) { return *status = foo(); }
...
if(foo_wrapper(&status) != eSuccess) goto Error;

甚至:

int status_assign(int *dest,int src) { return *dest = src; }
...
if(status_assign(&status,foo()) != eSuccess) goto Error;

另一方面,这应该不是问题,因为如果您使用 -Wall 编译,您应该,您将得到:

warning: suggest parentheses around assignment used as truth value

就我个人而言,当它是单个语句时,我认为大括号不是非常重要,但是如果你想要一个带大括号的单行,那么就这样做:

if((status = foo()) != eSuccess) { goto Error; }

有些人会喜欢它。有些人不会,但这不是世界上最重要的问题。但在您建议的宏之前,我更喜欢上述任何

比较这些:

PROPOGATE_METHOD(status,foo(),goto Error;);
if((status = foo()) != eSuccess) goto Error;

并排比较时,我真的看不出这个宏有什么作用。它不会使任何事情变得更清晰或更安全。没有宏,我可以确切地看到正在发生的事情,我不需要对此感到怀疑。宏有其用途,但就我在这里所见,这不是其中之一。

来自下面的评论

我明白了。我正在经历并重构代码库。我不喜欢用这些 if 语句来减少代码库,而更喜欢宏语句,因为

我能理解,但我真的鼓励你重新考虑。至少如果你被允许这样做。如果我要重构该代码库,那么摆脱该宏将具有很高的优先级。毕竟,重构是重写代码,使其在专注于设计和可读性的情况下变得更好。如果您不想这样做,请将括号放在 statusfunction 周围,然后离开。它不会让它变好,但也不会造成任何伤害。

如果是你写了那个宏,我不会用这个表达,但既然不是你,我可以用它。 “修复”该宏确实是在抛光粪便。不管你做什么,它永远不会发光,它永远是一团屎。

,

忽略该宏是否有用或令人困惑,以及 goto 的优点,请考虑宏/定义中的括号的用途。如果你有的话,这个:

#define FOO a + b
...
int y = x * FOO;

你最终得到的是 y = x * a + b(因为它只是文本替换,不是真正的变量),它与 y = (x * a) + b 相同。因此,在 (a + b) 中将 FOO 括起来可以解决这个问题。

这当然有类似的问题(在 x 内和宏外),有类似的解决方案:

#define FOO2(x) x * 123
...
int y = FOO2(a + b);

现在,你有

#define BAR(x) { x };

那里有类似的问题吗? x 应该包括哪些内容,括号将消除源自运算符优先级的类似问题?我真的没有看到这样的问题,在某种程度上,大括号已经可以保护 x 部分免受宏周围代码的影响。添加括号的效果只是强制 x 成为一个表达式,而不是一个完整的语句。

,

goto 语句 (goto label;) 不是表达式,因此您不能将它括起来(如果没有 goto label; 也不是,它甚至不是一个单独可识别的构造在 C 的语法中)。

即使你传递了一些可以用括号括起来的东西(例如,longjmp(jbuf,1)),在这种情况下({ HOOK; })用括号括起来也没有多大意义。

现在,如果您在 HOOK_EXPR * 2 之类的上下文中扩展它,那么括号将有助于强制 HOOK_EXPR* 更紧密地分组(假设您将 3+4 作为 { {1}}),但在这种情况下,您不需要它们。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...