转换为 `void` 的真正作用是什么?
What does casting to `void` really do?
像 (void)x;
这样的常用语句允许抑制关于未使用变量 x
的警告。但是如果我尝试编译以下内容,我会得到一些我不太理解的结果:
int main()
{
int x;
(short)x;
(void)x;
(int)x;
}
用 g++ 编译它,我收到以下警告:
$ g++ test.cpp -Wall -Wextra -o test
test.cpp: In function ‘int main()’:
test.cpp:4:13: warning: statement has no effect [-Wunused-value]
(short)x;
^
test.cpp:6:11: warning: statement has no effect [-Wunused-value]
(int)x;
^
所以我得出结论,转换为 void
与转换为任何其他类型非常不同,目标类型与 decltype(x)
相同或不同。我对可能的解释的猜测是:
- 这只是一个惯例,
(void)x;
而不是其他转换将抑制警告。所有声明同样没有任何效果。
- 这种差异在某种程度上与以下事实有关:
void x;
不是有效语句,而 short x;
是。
以下哪个更正确?如果 none,那么如何解释编译器警告的差异?
这条语句:
(void)x;
说 "Ignore the value of x." 没有 void
这样的类型 - 它是缺少类型。所以它与此有很大不同:
(int)x;
也就是说 "Treat x as if it were an integer." 当生成的整数被忽略时,您会收到警告(如果已启用)。
当您忽略什么都不是的东西时,GCC 不会将其视为问题 - 并且有充分的理由,因为强制转换为 void 是在 C 和 C++ 中显式忽略变量的惯用方法。
转换为 void 用于抑制编译器警告。 Standard 在 §5.2.9/4 中说,
Any expression can be explicitly converted to type “cv void.” The
expression value is discarded.
该标准不强制为未使用的局部变量或函数参数生成警告("diagnostic" 标准语)。同样,它也没有规定如何抑制此类警告。将变量表达式强制转换为 void
以抑制此警告已成为 C 和后来的 C++ 社区中的习语,因为结果不能以任何方式使用(除了 (int)x
),所以不太可能只是缺少相应的代码。例如:
(int)x; // maybe you meant f((int)x);
(void)x; // cannot have intended f((void)x);
(void)x; // but remote possibility: f((void*)x);
就个人而言,我觉得这个约定仍然太晦涩难懂,这就是为什么我更喜欢使用函数模板的原因:
template<typename T>
inline void ignore(const T&) {} // e.g. ignore(x);
然而,忽略函数参数的惯用方法是省略它们的名称(如上所示)。当我需要能够在条件编译代码(例如 assert
中命名函数参数时,我经常使用此函数。我发现例如以下比使用 #ifdef NDEBUG
更清晰:
void rate(bool fantastic)
{
assert(fantastic);
ignore(fantastic);
}
可能的用途:
auto it = list_.before_begin();
for (auto& entry : list_)
{
(void)entry; //suppress warning
++it;
}
现在迭代器'it'指向最后一个元素
像 (void)x;
这样的常用语句允许抑制关于未使用变量 x
的警告。但是如果我尝试编译以下内容,我会得到一些我不太理解的结果:
int main()
{
int x;
(short)x;
(void)x;
(int)x;
}
用 g++ 编译它,我收到以下警告:
$ g++ test.cpp -Wall -Wextra -o test
test.cpp: In function ‘int main()’:
test.cpp:4:13: warning: statement has no effect [-Wunused-value]
(short)x;
^
test.cpp:6:11: warning: statement has no effect [-Wunused-value]
(int)x;
^
所以我得出结论,转换为 void
与转换为任何其他类型非常不同,目标类型与 decltype(x)
相同或不同。我对可能的解释的猜测是:
- 这只是一个惯例,
(void)x;
而不是其他转换将抑制警告。所有声明同样没有任何效果。 - 这种差异在某种程度上与以下事实有关:
void x;
不是有效语句,而short x;
是。
以下哪个更正确?如果 none,那么如何解释编译器警告的差异?
这条语句:
(void)x;
说 "Ignore the value of x." 没有 void
这样的类型 - 它是缺少类型。所以它与此有很大不同:
(int)x;
也就是说 "Treat x as if it were an integer." 当生成的整数被忽略时,您会收到警告(如果已启用)。
当您忽略什么都不是的东西时,GCC 不会将其视为问题 - 并且有充分的理由,因为强制转换为 void 是在 C 和 C++ 中显式忽略变量的惯用方法。
转换为 void 用于抑制编译器警告。 Standard 在 §5.2.9/4 中说,
Any expression can be explicitly converted to type “cv void.” The expression value is discarded.
该标准不强制为未使用的局部变量或函数参数生成警告("diagnostic" 标准语)。同样,它也没有规定如何抑制此类警告。将变量表达式强制转换为 void
以抑制此警告已成为 C 和后来的 C++ 社区中的习语,因为结果不能以任何方式使用(除了 (int)x
),所以不太可能只是缺少相应的代码。例如:
(int)x; // maybe you meant f((int)x);
(void)x; // cannot have intended f((void)x);
(void)x; // but remote possibility: f((void*)x);
就个人而言,我觉得这个约定仍然太晦涩难懂,这就是为什么我更喜欢使用函数模板的原因:
template<typename T>
inline void ignore(const T&) {} // e.g. ignore(x);
然而,忽略函数参数的惯用方法是省略它们的名称(如上所示)。当我需要能够在条件编译代码(例如 assert
中命名函数参数时,我经常使用此函数。我发现例如以下比使用 #ifdef NDEBUG
更清晰:
void rate(bool fantastic)
{
assert(fantastic);
ignore(fantastic);
}
可能的用途:
auto it = list_.before_begin();
for (auto& entry : list_)
{
(void)entry; //suppress warning
++it;
}
现在迭代器'it'指向最后一个元素