【问题标题】:What does casting to `void` really do? [duplicate]强制转换为 `void` 真的有什么作用? [复制]
【发布时间】:2016-03-21 05:18:32
【问题描述】:

(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; 是一个事实有关。

如果有的话,哪一个更正确?如果没有,那么如何解释编译器警告的差异?

【问题讨论】:

  • 这种强制转换抑制警告只是编译器之间的约定。 C++ 标准根本没有提到“语句无效”的警告。
  • @cigien 尽管问题表面上很相似,但这个问题询问了转换为 void 和转换为其他类型之间的差异机制,而另一个询问了为什么要这样做投射到void。但是,由于这个问题有一个令人满意的答案,我不会费心改变它并投票重新开放。这条评论只是为了回答自动生成的“这能回答你的问题吗?”。 TLDR:不。
  • 我明白你在说什么,总的来说,我会将“什么”和“为什么”问题分开。但在这种情况下,“它做什么”与“为什么这样做”方面密切相关,所以我认为值得将它们联系起来。除了禁止警告之外,没有理由这样做(即强制转换为 void),并且两个帖子上的所有答案基本上都说同样的话。

标签: c++ casting compiler-warnings void suppress-warnings


【解决方案1】:

此声明:

(void)x;

说“忽略 x 的值”。没有像void 这样的类型 - 它是没有类型。所以和这个有很大的不同:

(int)x;

上面写着“将 x 视为整数”。当结果整数被忽略时,您会收到警告(如果已启用)。

当你忽略一些无关紧要的东西时,GCC 不会认为它是一个问题——而且有充分的理由,因为强制转换为 void 是在 C 和 C++ 中显式忽略变量的惯用方式。

【讨论】:

  • 我从来没有这样想过,但我有点困惑,你认为你可以举一个例子来阐明将变量转换为void的概念吗?
  • 我很确定有“void 这样的类型”。请参阅 [basic.types]。
  • @Sacert: (void)x 正在将一个变量强制转换为 void。你自己说的。但是一旦你这样做了,你就不能再用它做更多的事情了,因为 void 表达式没有任何价值。
  • 将返回结果强制转换为 void ((void)foo()) 表示您故意忽略返回值更有用。我唯一可以将变量转换为 void 的情况是,如果该变量仅在某些 #ifdef 代码中使用,并且您希望在不包含该代码时抑制警告。
  • @MartinBonner:是的,当变量仅在assert() 中使用时,通常会将变量强制转换为 void,否则会在发布版本中产生警告。
【解决方案2】:

强制转换为 void 用于抑制编译器警告。 Standard 在 §5.2.9/4 中说,

任何表达式都可以显式转换为“cv void”类型。这 表达式值被丢弃。

【讨论】:

    【解决方案3】:

    该标准不强制要求为未使用的局部变量或函数参数生成警告(标准术语为“诊断”)。同样,它也没有规定如何禁止此类警告。将变量表达式强制转换为 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);
    }
    

    【讨论】:

    • 从 C++17 开始,您可以使用 [[maybe_unused]] 属性而不是所有这些“创造性”的方式来忽略参数。
    【解决方案4】:

    可能的用途:

    auto it = list_.before_begin();
    for (auto& entry : list_)
    {
        (void)entry; //suppress warning
        ++it;
    }
    

    现在迭代器'it'指向最后一个元素

    【讨论】:

    • 问题不是“什么时候有用”,而是“它有什么作用”。
    • 例如就像评论中提到的那样:“抑制警告”
    猜你喜欢
    • 2011-05-09
    • 2012-03-17
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 2012-04-12
    • 2011-05-01
    • 2016-08-05
    相关资源
    最近更新 更多