为什么alignas说明符会在Clang上抛出错误?

5 c++ memory-alignment c++11

根据该标准,new表达式的语法允许alignas提供说明符以及其他属性说明符。我见过其他代码使用这个,但 GCC 会忽略属性说明符,即使它在最大对齐范围内,并且 Clang 会抛出错误。

  • alignas说明符在表达式中实际上有效吗new
  • 如果它有效,为什么 Clang 会拒绝我的代码,为什么无论我请求什么对齐方式,GCC 都会忽略我的属性?

我并不是想解决特定问题,我只是想了解标准。

    int* example = new alignas(16) int[2];
    // alignof(std::max_align_t) = 16
    // sizeof(int) = 4, sizeof(example) = 8
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会:

prog.cc: In function 'int main()':
prog.cc:7:41: warning: attribute ignored [-Wattributes]
    7 |     int* example = new alignas(16) int[2];
      |                                         ^
prog.cc:7:41: note: an attribute that appertains to a type-specifier is ignored
Run Code Online (Sandbox Code Playgroud)

铛:

 prog.cc:7:24: error: an attribute list cannot appear here:
               int* example = new alignas(16) int[2];
Run Code Online (Sandbox Code Playgroud)

可在最新的 GCC 和 Clang 上重现,例如: http: //cpp.sh/3hfl7

参考:

http://eel.is/c++draft/expr.new#nt:new-表达式

new-type-id:
    type-specifier-seq new-declarator opt

type-specifier-seq:
    type-specifier attribute-specifier-seq opt
    type-specifier type-specifier-seq
Run Code Online (Sandbox Code Playgroud)

(语法允许 new-type-id -> type-specifier-seq -> attribute-specifier-seq -> attribute-specifier ->alignment-specifier)

attribute-specifier-seq可以包含对齐说明符。

Bri*_*ian 1

好吧,您引用的语法指出, type- specifier-seq中出现的attribute- specifier- seq必须出现在所有type-specifiers之后。因此,您必须将其放在这里,以便int根据[dcl.type]/1使属性属于前面的内容:

new int attribute-specifier-seq [2];
Run Code Online (Sandbox Code Playgroud)

您必须将其放在这里,以便根据[expr.new]/6使属性属于数组类型:

new int [2] attribute-specifier-seq;
Run Code Online (Sandbox Code Playgroud)

您还可以将它们组合起来:数组类型和元素类型可以具有不同的属性。但我认为语法不允许您将属性放在int.

至于对齐说明符的具体问题:标准既没有明确允许也没有明确禁止将对齐说明符应用于类型说明符类型ID ( [dcl.align]/1 )。Clang 似乎将该标准解释为禁止它。GCC 似乎将该标准解释为允许;但是,由于该标准没有为属于类型的对齐说明符指定任何语义,因此会发出警告。考虑:

struct S {
    int x alignas(16);
    int alignas(16) y;
};
Run Code Online (Sandbox Code Playgroud)

这里,S::x将有 16 的对齐要求,但对齐说明符S::y是没有意义的。因此,如果您编写int alignas(16) y,GCC 会警告您,以便您意识到您将其放在错误的位置。

要强制分配的内存在 16 字节边界上对齐,请使用放置语法显式调用operator new带有对齐参数的重载:

int* x = new (std::align_val_t(16)) int [2];
Run Code Online (Sandbox Code Playgroud)