【问题标题】:What does the standard say implementations should do upon finding unknown attributes?标准说实现在发现未知属性时应该做什么?
【发布时间】:2016-04-23 14:02:49
【问题描述】:

C++11 带来了对所谓“通用属性”的支持,以及两个标准属性noreturncarries_dependency。 C++14 将deprecated 添加到表中。但是,我找不到任何关于在找到他们不知道的属性时标准强制执行哪些实现。也许只是标准没有说明这件事。不过,我想知道。

实际上,gcc 和 clang 都有关于这种情况的警告,可能会被禁用。特别是,gcc 会给出警告 'some_attribute' attribute directive ignored (-Wattributes),而 clang 会发出警告 unknown attribute 'some_attribute' ignored (-Wunknown-attributes)。不过,我无法找到这些选项的文档; GCC 的 Warning Options 页面仅提及 -Wattributes,而 Clang 似乎甚至没有类似的列表。

我为什么要问这个?嗯,一些特定于实现的属性很有趣。以 GCC 的 nonnull 属性为例。我们可以很高兴地用它来注释一些函数:

[[gnu::nonnull]] void my_function ( char * a , int * b );

如果实现知道该属性,一切都很好。但如果没有,我们还能期待什么?

  • 它会忽略它,并且这种行为得到了标准的支持。我们可以继续添加我们在在线文档中找到的每个有趣的属性。特别是,这将允许混合 visibilitydllexport 而没有尽可能多的 #ifs ~yay!

    #if BUILDING_DLL
    #define DLLEXIMPORT dllexport
    #else
    #define DLLEXIMPORT dllimport
    #endif
    
    // even if MSVC doesn't support specifying dllexport this way, Clang does, and it can
    // compile MSVC-compatible objects
    [[gnu::visibility("default"),DLLEXIMPORT]] void api_function ();
    
  • 它抱怨它并且这种行为得到了标准的支持。 哦!我们将不得不推出一些丑陋的机器来防止未知属性落入那些讨厌的实现之手。

    只有一个属性,这很容易,因为标准允许空属性列表:

    #if SOMETHING
    #define ATTRIBUTE_GNU_NONNULL gnu::nonnull
    #else
    #define ATTRIBUTE_GNU_NONNULL
    #endif
    
    // if ATTRIBUTE_GNU_NONNULL is defined to nothing, all that happens is that we get
    // an empty attribute list, which is 'standardly valid'
    [[ATTRIBUTE_GNU_NONNULL]] void my_function ( char * a , int * b );
    

    但是,如果有多个属性,事情就会变得更加棘手:

    #if SOMETHING
    #define ATTRIBUTE_GNU_NONNULL gnu::nonnull
    #else
    #define ATTRIBUTE_GNU_NONNULL
    #endif
    
    #if SOMETHING
    #define ATTRIBUTE_GNU_VISIBILITY( visibility_type ) gnu::visibility(#visibility_type)
    #else
    #define ATTRIBUTE_GNU_VISIBILITY( visibility_type )
    #endif
    
    // if any of the two macros is defined to nothing, it expands to [[,blah_blah]]
    // or [[blah_blah,]]  -  both of which are invalid
    [[ATTRIBUTE_GNU_NONNULL,ATTRIBUTE_GNU_VISIBILITY(default)]] void my_function
    ( char * a , int * b );
    

    想到的更丑陋的解决方案是使用组合属性的宏,如下所示:

    #if SOMETHING
    #define ATTRIBUTES_GNU_NONNULL_AND_GNU_VISIBILITY( visibility_type ) \
        gnu::nonnull,gnu::visibility(#visibility_type)
    #else
    #define ATTRIBUTES_GNU_NONNULL_AND_GNU_VISIBILITY( visibility_type )
    #endif
    
    [[ATTRIBUTES_GNU_NONNULL_AND_GNU_VISIBILITY(default)]] void my_function
    ( char * a , int * b );
    

    但我会因为这个:)而被击中头部。

因此,如果标准要求实现忽略未知属性,我可以选择我在在线文档中找到的每一个相关属性,而无需担心和丑陋的解决方案——这就是我的兴趣。

【问题讨论】:

  • 不出所料:[dcl.attr.grammar]/5 对于本国际标准中未指定的属性标记,行为是实现定义的。
  • @user657267:请在回答部分回答。如果您的评论是错误的(不是),我们将无法对其投反对票。它不能被审查。它不计入问题是否已被回答。等等等等。评论是为了要求澄清。
  • 这个问题的格式很好,但我必须使用“无研究工作”的否决按钮,因为只需阅读标准中关于属性的章节即可轻松找到答案。
  • @LightnessRacesinOrbit 不幸的是,我无法访问该标准。我很确定允许空属性列表只是因为它在 proposal paper 中提到(在修订版 2 中的更改中:allow empty attribute-lists)——但是,即便如此,我也没有有确定性,因为在进入标准之前情况可能会发生变化。

标签: c++ c++14


【解决方案1】:

7.6.1/3

[...] 有条件地支持使用属性范围令牌,并具有实现定义的行为。 [注意:每个实现都应该为属性范围令牌中的属性命名空间选择一个独特的名称。 ——尾注]

7.6.1/5

对于本国际标准中未指定的属性标记,其行为是实现定义的。

简而言之,答案是:检查编译器文档。

【讨论】:

    【解决方案2】:

    [C++14: 7.6.1/5]: 对于本国际标准中未指定的 attribute-token,其行为由实现定义。

    因此,如果您希望在遇到无法识别的属性时获得任何“保证”行为,则必须查阅实现的文档。

    【讨论】:

    • 请注意,这在 C++17 中发生了变化,现在“任何无法被实现识别的属性标记都会被忽略”。
    猜你喜欢
    • 2011-06-20
    • 2014-01-25
    • 2018-08-01
    • 1970-01-01
    • 2020-04-28
    • 2013-09-09
    • 1970-01-01
    • 2021-03-26
    • 2020-06-03
    相关资源
    最近更新 更多