【问题标题】:Correctly using C++20 `[likely]]`/`[[unlikely]]` in `switch` statements在 `switch` 语句中正确使用 C++20 `[likely]]`/`[[unlikely]]`
【发布时间】:2021-06-04 08:20:14
【问题描述】:

C++20 有方便的[[likely]]/[[unlikely]] 属性来指导代码生成。例如,您可以指定一个分支很可能被:

if (b) [[likely]] { /*...*/ }

同样,可以在switch 语句中使用这些属性。 . .不知何故? The documentation 建议以下示例(稍微格式化):

switch (i) {
    case 1:
        [[fallthrough]];
    [[likely]] case 2:
        return 1;
}

这显然意味着[[likely]]/[[unlikely]]case 语句之前。互联网似乎几乎普遍宣传这种用法。

但是,请考虑以下类似代码(我所做的只是将[[likely]] 移动到另一个case):

switch (i) {
    [[likely]] case 1:
        [[fallthrough]];
    case 2:
        return 1;
}

这无法在 clang 上编译!虽然这可能与a compiler bug with [[fallthrough]] 有关,但它让我看到了标准。 relevant standard 有以下示例(参见§VII):

鼓励实现针对正在执行的情况进行优化(例如,a 在以下代码中具有值 1):

switch (a) {
    case 1: [[likely]]
        foo();
        break;
    //...
}

即属性出现在 case 标签之后,而不是之前。

所以。 . .是哪一个?顺便说一句,我希望标准是正确的,但这实际上是一个提案,而不是真正的标准 AFAICT——它可能已经改变了。而且,我希望文档至少在基本语法方面是正确的——除了它甚至无法编译。

【问题讨论】:

    标签: c++ attributes switch-statement c++20 branch-prediction


    【解决方案1】:

    这两个例子都是有效的,而且 Clang 出现了一个错误。 C++20 最新标准草案中的相关措辞是

    [dcl.attr.likelihood]

    1 属性标记likelyunlikely 可以应用于标签或语句。

    语句和标记语句的相关语法产生式在适当的位置具有属性说明符序列。

    [stmt.pre]

    statement:
      labeled-statement
      attribute-specifier-seq expression-statement
      attribute-specifier-seq compound-statement
      attribute-specifier-seq selection-statement
      attribute-specifier-seq iteration-statement
      attribute-specifier-seq jump-statement
      declaration-statement
      attribute-specifier-seq try-block
    

    [stmt.label]

    labeled-statement:
      attribute-specifier-seq identifier : statement
      attribute-specifier-seq case constant-expression : statement
      attribute-specifier-seq default : statement
    

    switch (i) {
        case 1:
            [[fallthrough]];
        [[likely]] case 2:
            return 1;
    }
    

    该属性适用于case 2:,其中

    switch (a) {
        case 1: [[likely]]
            foo();
            break;
        //...
    }
    

    它适用于声明foo();

    【讨论】:

    • 虽然简洁很好,但我觉得语言语法规则在这里高度相关。另外,我很难看出[[likely]] 应用于foo();case 语句之间的区别,因为(在fallthrough 或goto 之外)case 语句是唯一的方法@可以联系到 987654335@。当然,我可以看到 [[likely]] foo(); 作为一个孤立的构造工作,但论文确实明确表示这会影响 case 。 . .
    • @imallett - 它它应该影响案件(但是不是转到标签),但是那里提出的规范性措辞只提到了陈述。该提案也没有涉及所需的语法更改。该标准包含更精致的措辞。你看不出有什么不同,因为没有。规范性措辞只是为了允许更灵活的放置而设计。
    猜你喜欢
    • 2019-11-27
    • 1970-01-01
    • 2020-09-01
    • 2016-12-26
    • 1970-01-01
    • 2012-04-14
    • 1970-01-01
    • 2022-12-01
    • 1970-01-01
    相关资源
    最近更新 更多