虚空铸造宏观解释

时间:2016-09-22 01:18:29

标签: c++

希望对以下一段代码得到一些澄清/解释

#define NOOP(x) ((void)(x))

void my_function(int x)
{
     NOOP(x);
}

此宏可防止未使用的参数警告。

我有两个问题 -

  1. 因此,我们通过使用此宏来使任何x无效。什么' S 当我们无效的东西时真的发生了吗?
  2. 为什么在(void)(x)
  3. 附近有一组额外的括号

    由于

3 个答案:

答案 0 :(得分:2)

就发生的事情而言,它绝对没有,这就是重点。只是对变量的引用,但绝对不做任何事情。编译器尽职尽责地处理它,注意到使用了参数,然后将所有内容抛弃,并且不生成任何实际代码。

就括号而言:

最好对可能在表达式中使用的宏使用括号,即使不需要它也是如此。

例如,考虑一个假设代码中的简单宏,它在屏幕上绘制一个窗口。执行此操作的库在窗口周围添加了一个边框,例如,长度为6像素。该宏计算窗口的总宽度。这个宏的一个简单的实现将是:

#define ACTUAL_WIDTH(w)  w+6

现在,假设您的代码想要计算两个窗口的实际宽度。两个窗口都是100像素宽:

int total_width=ACTUAL_WIDTH(100)*2;

您认为发生了什么?回想一下,宏替换基本上只是一个简单的文本替换,所以这是实际编译的内容:

int total_width=100+6*2;

哪个是完全错误的。您希望宏中有一组额外的括号,以便编译正确的代码:

int total_width=(100+6)*2;

这就是为什么你经常会在宏中看到一组可以在表达式中使用的括号。不仅如此,像这样的宏也会在其参数周围加上括号,所以它可能是:

#define ACTUAL_WIDTH(w)  ((w)+6)

这就是为什么你在宏中看到一组额外的括号。更容易养成一种习惯,即始终将它们粘贴在你写的每一个宏中并且安全;如果真的需要与否,不要浪费时间计算出来。

使用良好的编程习惯可以避免许多常见的错误。

答案 1 :(得分:2)

来自C++14 standard working draft from November 2014的第5.2.9节第6段:

  

任何表达式都可以显式转换为cv void类型,在这种情况下它变成一个废弃值表达式。

正如其他人所说,额外的括号通过有效地隔离可能存在于其周围的代码中的表达式来禁止任何不良影响。虽然在这种情况下,我认为通过不包括外括号在实际应用中不会感觉到任何不良影响,特别是如果你只是使用它来避免函数中未使用的变量警告。将它们排除在外是不值得冒任何风险的。

为了证明这一点,我提出了一个非常人为的例子,导致无意中执行代码,因为有些运算符的优先级高于C风格的代码。

#include <iostream>

#define NOOP(x) ((void)(x))
#define MYNOOP(x) (void) (x)

struct A
{
  bool operator()(void) {
    std::cout << "Called function unintentionally" << std::endl;
    return true;
  }
};

int main() {
  A i;
  MYNOOP(i)();
  //NOOP(i)(); // error: called object type 'void' is not a function or function pointer
  return 0;
}

答案 2 :(得分:1)

正如你所说,你的代码不会显示未使用的变量警告,因为你使用的是变量'x',但是你只是对它做了什么,你将它传递给一个没有重要作用的函数(NOOP(x) ) - 没有什么重要但是,编译器看到你正在尝试使用x变量)所以它不告诉你你没有使用你的变量