【问题标题】:Why should I avoid macros in C++? [closed]为什么我应该避免 C++ 中的宏? [关闭]
【发布时间】:2013-06-11 11:34:26
【问题描述】:

我读过很多书和教程,我应该避免在 c++ 中使用宏。很好,但为什么呢?我不明白。它们非常有用,经常在 C 语言中使用。

有人可以(非常)详细地解释一下,为什么我应该在 C++ 中避免使用它们?

【问题讨论】:

  • 书籍没有解释原因吗?
  • “为什么我应该避免在 C++ 中使用宏”的快速 google 提出了这个:securecoding.cert.org/confluence/display/cplusplus/…
  • 好吧,你应该避免使用宏,因为它的某些其他功能提供了更好的替代方案;否则使用宏。您担心什么样的情况?
  • @juanchopanza 悲伤但真实,不,他们没有:(
  • 我脑海中的第一个想法:缺乏命名空间支持,难以调试,容易出现错误(范围错误),而不是 C++ 方式(即 C++ 通常提供更好的替代方案),宏的副作用多次引用一个参数(想想MYMACRO(i++),其中MYMACRO类似于something((X), ... , (X), ...)

标签: c++ macros


【解决方案1】:

宏不遵守范围规则,而是在文本级别操作,而不是在语法级别。由此产生了许多可能导致奇怪的、难以隔离的错误的陷阱。

考虑以下众所周知的例子:

#define max(a, b) ((a) < (b) ? (b) : (a))
⋮
int i = max(i++, j++);

在这种情况下,首选的替代方法是函数模板:

template <typename T>
T max(const T & a, const T & b) { return a < b ? b : a; }

这是另一个导致微妙问题的案例:

#define CHECK_ERROR(ret, msg) \
    if (ret != STATUS_OK) { \
        fprintf(stderr, "Error %d: %s\n", ret, msg); \
        exit(1); \
    }
⋮
if (ready)
    CHECK_ERROR(try_send(packet), "Failed to send");
else
    enqueue(packet);

您可能认为解决方案就像将CHECK_ERROR 的内容包装在{ … } 中一样简单,但是由于;else 之前,这不会编译。

为避免上述问题(else 附加到CHECK_ERRORif 而不是外部if),应将此类宏包装在do … while (false) 中,如下所示:

#define CHECK_ERROR(ret, msg) \
  do { \
    if (ret != STATUS_OK) { \
        fprintf(stderr, "Error %d: %s\n", ret, msg); \
        exit(1); \
    } \
  while (false)

这对宏的含义没有影响,但确保整个块始终被视为单个语句,并且不会以令人惊讶的方式与 if 语句交互。

长话短说,宏在许多层面都是危险的,因此只能作为最后的手段使用。

【讨论】:

  • 但它也一样,对吧?为什么不用宏而不是模板
  • @Davlog:想想宏是如何扩展的:max(i++, j++)((i++) &lt; (j++) ? (j++) : (i++))。请注意,无论哪个变量较高,最终都会增加两次。这是宏执行文本替换这一事实的根本问题。
猜你喜欢
  • 2010-09-29
  • 2011-07-10
  • 2011-03-10
  • 2021-06-03
  • 2016-06-07
  • 2011-05-09
  • 2016-06-30
  • 2020-03-24
相关资源
最近更新 更多