在c++ 11中,哪里可以使用alignas() ?

时间:2022-01-19 20:27:20

In an effort to standardize my code and make it more portable, I replaced

为了标准化我的代码并使其更可移植性,我替换了它

#ifdef __GNUC__
typedef __attribute__((aligned(16))) float aligned_block[4];
#else
typedef __declspec(align(16)) float aligned_block[4];
#endif

with

typedef float alignas(16) aligned_block[4];

in C++11. However, gnu (4.8) doesn't like that but complains

在c++中11。然而,gnu(4.8)不喜欢这样,但是会抱怨

test.cc:3:9: warning: attribute ignored [-Wattributes]
  typedef float alignas(16) aligned_block[4];
                ^
test.cc:3:9: note: an attribute that appertains to a type-specifier is ignored

whereas clang 3.2 creates no warning (even with -Weverything -Wno-c++98-compat -pedantic). So I wonder whether my code above is correct and, more generally, where alignas() can and cannot be placed.

而clang 3.2则不会产生任何警告(即使使用- we - no-c+ 98-compat -pedantic)。因此,我想知道上面的代码是否正确,更一般地说,alignas()可以放置,也不能放置。

EDIT (Apr 2013):

编辑(2013年4月):

The relevant article from the standard is 7.6.2, in particular 7.6.2.1

本标准相关条款为7.6.2,特别是7.6.2.1

An alignment-specifier may be applied to a variable or to a class data member, but it shall not be applied to a bit-field, a function parameter, the formal parameter of a catch clause (15.3), or a variable declared with the register storage class specifier. An alignment-specifier may also be applied to the declaration of a class or enumeration type. An alignment-specifier with an ellipsis is a pack expansion (14.5.3).

一个aligni -specifier可以应用于一个变量或一个类数据成员,但它不能应用于一个位域、一个函数参数、catch子句的形式参数(15.3),或一个与寄存器存储类说明符声明的变量。也可以应用到类或枚举类型的声明中。带有省略号的对齐说明符是包展开(14.5.3)。

as already dug out by Red XIII. However, I'm not expert enough to know what this means for my test above.

已经被红色十三挖出来了。然而,我还不够专业,不知道这对我上面的测试意味着什么。

If the fact that clang accepts my attribute means anything, it's perhaps worth mentioning that when trying to use a using directive instead of a typedef, clang also complains. Also, contrary to a statement in an earlier version of this question, gcc does not only warn, but indeed ignores my wish for alignment.

如果clang接受我的属性这一事实意味着什么,那么值得一提的是,当尝试使用using指令而不是类型定义时,clang也会抱怨。此外,与前一个版本的问题相反,海湾合作委员会不仅提出警告,而且实际上忽略了我结盟的愿望。

4 个解决方案

#1


8  

You cannot apply an alignment to a typedef. In the C++ model of alignment specifiers, the alignment is an inseparable part of the type itself, and a typedef does not create a new type (it only provides a new name for an existing type) so it is not meaningful to apply an alignment specifier in a typedef declaration.

不能对类型定义应用对齐。在对齐说明符的c++模型中,对齐是类型本身不可分割的一部分,类型定义不创建新类型(它只为现有类型提供一个新名称),所以在类型定义声明中应用对齐说明符没有意义。

From [dcl.align] (7.6.2)p1:

从[dcl。对齐)p1(土壤质素):

An alignment-specifier may be applied to a variable or to a class data member [...]. An alignment-specifier may also be applied to the declaration or definition of a class (in an elaborated-type-specifier (7.1.6.3) or class-head (Clause 9), respectively) and to the declaration or definition of an enumeration (in an opaque-enum-declaration or enum-head, respectively (7.2)).

对变量或类数据成员(…)可以应用一个aligni -specifier。别名说明符也可用于类的声明或定义(分别在精化类型说明符(7.1.6.3)或类头(第9条)中),以及枚举的声明或定义(分别在opaque-enum声明或en -head中(7.2)))。

These are the only places where the standard says an alignment-specifier (alignas(...)) may be applied. Note that this does not include typedef declarations nor alias-declarations.

这些是标准中唯一可以应用的地方(alignas(…))。注意,这并不包括typedef声明和别名声明。

Per [dcl.attr.grammar] (7.6.1)p4:

/(dcl.attr。语法](7.6.1 p4):

If an attribute-specifier-seq that appertains to some entity or statement contains an attribute that is not allowed to apply to that entity or statement, the program is ill-formed.

如果属于某个实体或语句的属性-specifier-seq包含不允许应用于该实体或语句的属性,则程序是不良的。

This wording was intended to apply to alignas as well as the other forms of attribute that may appear within an attribute-specifier-seq, but was not correctly updated when alignment switched from being a "real" attribute to being a different kind of attribute-specifier-seq.

这一措辞旨在应用于alignas以及其他可能出现在属性-specifier-seq中的属性形式,但当对齐从“真实”属性转变为不同类型的属性-specifier-seq时,并没有得到正确的更新。

So: your example code using alignas is supposed to be ill-formed. The C++ standard does not currently explicitly say this, but it also does not permit the usage, so instead it currently would result in undefined behavior (because the standard does not define any behavior for it).

因此:使用alignas的示例代码被认为是不完整的。c++标准目前没有明确地说明这一点,但是它也不允许使用,所以它现在会导致未定义的行为(因为标准没有为它定义任何行为)。

#2


26  

I think you just placed the alignas in the wrong position. If you move it directly after the identifier, both GCC and Clang are happy and apply the alignment:

我想你刚刚把alignas放到了错误的位置。如果您直接在标识符后面移动它,GCC和Clang都很高兴并应用对齐:

typedef float aligned_block alignas(16) [4];
typedef float aligned_block [4] alignas(16);

this is also true if you use using, where the difference also becomes more apparent. Here are two versions that are not accepted by GCC (warning, alignment ignored):

如果您使用using,这也是正确的,其中的差异也变得更加明显。以下是GCC不接受的两个版本(警告,对齐被忽略):

using aligned_block = float alignas(16)[4];
using aligned_block = float[4] alignas(16);

and here's the accepted one:

这是大家公认的

using aligned_block alignas(16) = float[4];

I think that GCC applies

我认为GCC是适用的

7.1.3 The typedef specifier [dcl.typedef]

2 A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. It has the same semantics as if it were introduced by the typedef specifier. [...]

一个typedef名称也可以通过一个alias声明引入。use关键字后面的标识符成为一个typedef-name,而标识符后面的可选属性-specifier-seq则属于这个typedef-name。它具有与typedef说明符引入的相同的语义。[…]

(emphasis mine)

(强调我的)

The above is quite clear for using, the rules for typedef are spread through several paragraphs, including at the end of §8.3/1, where you find:

上面的使用是非常清楚的,类型定义的规则是通过几个段落,传播包括§8.3/1结束时,你会发现:

8.3 Meaning of declarators [dcl.meaning]

1 [...] The optional attribute-specifier-seq following a declarator-id appertains to the entity that is declared.

1[…[参考译文]在声明符id之后的可选属性—specifier-seq属于被声明的实体。

(again, emphasis mine)

(再次强调我的)


Update: The above answer concentrated on where the alignas has to be placed, not on its exact meaning. After thinking about it some more, I still think that the above should be valid. Consider:

更新:上面的答案集中在alignas必须放在哪里,而不是它的确切含义。在进一步思考之后,我仍然认为上面的观点是正确的。考虑:

7.6.2 Alignment Specifier [dcl.align]

1An alignment-specifier may be applied to a variable or to a class data member, but it shall not be applied to a bit-field, a function parameter, an exception-declaration (15.3), or a variable declared with the register storage class specifier. An alignment-specifier may also be applied to the declaration or definition of a class (in an elaborated-type-specifier (7.1.6.3) or class-head (Clause 9), respectively) and to the declaration or definition of an enumeration (in an opaque-enum-declaration or enum-head, respectively (7.2)). An alignment-specifier with an ellipsis is a pack expansion (14.5.3).

一个对齐说明符可以应用于变量或类数据成员,但不能应用于位域、函数参数、异常声明(15.3)或寄存器存储类说明符声明的变量。别名说明符也可用于类的声明或定义(分别在精化类型说明符(7.1.6.3)或类头(第9条)中),以及枚举的声明或定义(分别在opaque-enum声明或en -head中(7.2)))。带有省略号的对齐说明符是包展开(14.5.3)。

It lists cases where it can be clearly applied and it lists cases where it clearly can not be applied. The above question's example is neither.

它列出了可以清楚地应用它的情况,并列举了它显然不能应用的情况。以上问题的例子两者都不是。

One could also argue that the type alias created by typedef or using is carrying the alignment specification as part of the aliased type. This alias can than be used to create a variable, etc. as allowed by 7.6.2p1 but not to create a variable with register, etc.

还可以认为,typedef或using创建的类型别名将对齐规范作为别名类型的一部分。这个别名可以用来创建一个变量,如7.6.2p1所允许的,但是不能使用register等来创建一个变量。

In that sense I think that the attribute specifier is applied (in the sense of 7.6.2) in a deferred way and thus OPs example should still be valid when the alignment specification is put in the syntactically correct place.

从这个意义上说,我认为属性说明符以一种延迟的方式应用(在7.6.2的意义上),因此,当对齐规范放在语法正确的位置时,OPs示例应该仍然有效。

#3


6  

Draft C++11 standard http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf says about it (Alignment-specifier is of the form alignas ( assignment-expression )):

C++11标准:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf。(align-specifier是表单alignas(赋值表达式)):

7.6.2 Alignment specifier [dcl.align]

土壤质素对齐说明符(dcl.align)

1 An alignment-specifier may be applied to a variable or to a class data member, but it shall not be applied to a bit-field, a function parameter, the formal parameter of a catch clause (15.3), or a variable declared with the register storage class specifier. An alignment-specifier may also be applied to the declaration of a class or enumeration type. An alignment-specifier with an ellipsis is a pack expansion.

1可以对变量或类数据成员应用对齐说明符,但不能对位域、函数参数、catch子句(15.3)的形式参数或寄存器存储类说明符声明的变量应用。别名说明符也可以应用于类或枚举类型的声明。一个带有省略号的aligni -specifier是一个包扩展。

I found this original proposal http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1877.pdf , it says:

我在http://www.open- std.org/jtc1/sc22/wg21/docs/2005 /n1877.pdf中找到了这个原始建议:

The alignment-specifier does not become part of the type, but it is possible to create a class type with aligned member variable(s).

标识符不会成为类型的一部分,但是可以使用对齐的成员变量创建类类型。

with this example:

用这个例子:

// Wrong attempt: Listing 6)
typedef double align_by<0x10000> hwDoubleVector; // Error!
Void clear(hwDoubleVector &toClear, unsigned size);

Looks like it's illegal to use it with typedef.

看起来在typedef中使用它是非法的。

#4


-1  

Try:

试一试:

typedef float alignas(16) aligned_block[4];

#1


8  

You cannot apply an alignment to a typedef. In the C++ model of alignment specifiers, the alignment is an inseparable part of the type itself, and a typedef does not create a new type (it only provides a new name for an existing type) so it is not meaningful to apply an alignment specifier in a typedef declaration.

不能对类型定义应用对齐。在对齐说明符的c++模型中,对齐是类型本身不可分割的一部分,类型定义不创建新类型(它只为现有类型提供一个新名称),所以在类型定义声明中应用对齐说明符没有意义。

From [dcl.align] (7.6.2)p1:

从[dcl。对齐)p1(土壤质素):

An alignment-specifier may be applied to a variable or to a class data member [...]. An alignment-specifier may also be applied to the declaration or definition of a class (in an elaborated-type-specifier (7.1.6.3) or class-head (Clause 9), respectively) and to the declaration or definition of an enumeration (in an opaque-enum-declaration or enum-head, respectively (7.2)).

对变量或类数据成员(…)可以应用一个aligni -specifier。别名说明符也可用于类的声明或定义(分别在精化类型说明符(7.1.6.3)或类头(第9条)中),以及枚举的声明或定义(分别在opaque-enum声明或en -head中(7.2)))。

These are the only places where the standard says an alignment-specifier (alignas(...)) may be applied. Note that this does not include typedef declarations nor alias-declarations.

这些是标准中唯一可以应用的地方(alignas(…))。注意,这并不包括typedef声明和别名声明。

Per [dcl.attr.grammar] (7.6.1)p4:

/(dcl.attr。语法](7.6.1 p4):

If an attribute-specifier-seq that appertains to some entity or statement contains an attribute that is not allowed to apply to that entity or statement, the program is ill-formed.

如果属于某个实体或语句的属性-specifier-seq包含不允许应用于该实体或语句的属性,则程序是不良的。

This wording was intended to apply to alignas as well as the other forms of attribute that may appear within an attribute-specifier-seq, but was not correctly updated when alignment switched from being a "real" attribute to being a different kind of attribute-specifier-seq.

这一措辞旨在应用于alignas以及其他可能出现在属性-specifier-seq中的属性形式,但当对齐从“真实”属性转变为不同类型的属性-specifier-seq时,并没有得到正确的更新。

So: your example code using alignas is supposed to be ill-formed. The C++ standard does not currently explicitly say this, but it also does not permit the usage, so instead it currently would result in undefined behavior (because the standard does not define any behavior for it).

因此:使用alignas的示例代码被认为是不完整的。c++标准目前没有明确地说明这一点,但是它也不允许使用,所以它现在会导致未定义的行为(因为标准没有为它定义任何行为)。

#2


26  

I think you just placed the alignas in the wrong position. If you move it directly after the identifier, both GCC and Clang are happy and apply the alignment:

我想你刚刚把alignas放到了错误的位置。如果您直接在标识符后面移动它,GCC和Clang都很高兴并应用对齐:

typedef float aligned_block alignas(16) [4];
typedef float aligned_block [4] alignas(16);

this is also true if you use using, where the difference also becomes more apparent. Here are two versions that are not accepted by GCC (warning, alignment ignored):

如果您使用using,这也是正确的,其中的差异也变得更加明显。以下是GCC不接受的两个版本(警告,对齐被忽略):

using aligned_block = float alignas(16)[4];
using aligned_block = float[4] alignas(16);

and here's the accepted one:

这是大家公认的

using aligned_block alignas(16) = float[4];

I think that GCC applies

我认为GCC是适用的

7.1.3 The typedef specifier [dcl.typedef]

2 A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. It has the same semantics as if it were introduced by the typedef specifier. [...]

一个typedef名称也可以通过一个alias声明引入。use关键字后面的标识符成为一个typedef-name,而标识符后面的可选属性-specifier-seq则属于这个typedef-name。它具有与typedef说明符引入的相同的语义。[…]

(emphasis mine)

(强调我的)

The above is quite clear for using, the rules for typedef are spread through several paragraphs, including at the end of §8.3/1, where you find:

上面的使用是非常清楚的,类型定义的规则是通过几个段落,传播包括§8.3/1结束时,你会发现:

8.3 Meaning of declarators [dcl.meaning]

1 [...] The optional attribute-specifier-seq following a declarator-id appertains to the entity that is declared.

1[…[参考译文]在声明符id之后的可选属性—specifier-seq属于被声明的实体。

(again, emphasis mine)

(再次强调我的)


Update: The above answer concentrated on where the alignas has to be placed, not on its exact meaning. After thinking about it some more, I still think that the above should be valid. Consider:

更新:上面的答案集中在alignas必须放在哪里,而不是它的确切含义。在进一步思考之后,我仍然认为上面的观点是正确的。考虑:

7.6.2 Alignment Specifier [dcl.align]

1An alignment-specifier may be applied to a variable or to a class data member, but it shall not be applied to a bit-field, a function parameter, an exception-declaration (15.3), or a variable declared with the register storage class specifier. An alignment-specifier may also be applied to the declaration or definition of a class (in an elaborated-type-specifier (7.1.6.3) or class-head (Clause 9), respectively) and to the declaration or definition of an enumeration (in an opaque-enum-declaration or enum-head, respectively (7.2)). An alignment-specifier with an ellipsis is a pack expansion (14.5.3).

一个对齐说明符可以应用于变量或类数据成员,但不能应用于位域、函数参数、异常声明(15.3)或寄存器存储类说明符声明的变量。别名说明符也可用于类的声明或定义(分别在精化类型说明符(7.1.6.3)或类头(第9条)中),以及枚举的声明或定义(分别在opaque-enum声明或en -head中(7.2)))。带有省略号的对齐说明符是包展开(14.5.3)。

It lists cases where it can be clearly applied and it lists cases where it clearly can not be applied. The above question's example is neither.

它列出了可以清楚地应用它的情况,并列举了它显然不能应用的情况。以上问题的例子两者都不是。

One could also argue that the type alias created by typedef or using is carrying the alignment specification as part of the aliased type. This alias can than be used to create a variable, etc. as allowed by 7.6.2p1 but not to create a variable with register, etc.

还可以认为,typedef或using创建的类型别名将对齐规范作为别名类型的一部分。这个别名可以用来创建一个变量,如7.6.2p1所允许的,但是不能使用register等来创建一个变量。

In that sense I think that the attribute specifier is applied (in the sense of 7.6.2) in a deferred way and thus OPs example should still be valid when the alignment specification is put in the syntactically correct place.

从这个意义上说,我认为属性说明符以一种延迟的方式应用(在7.6.2的意义上),因此,当对齐规范放在语法正确的位置时,OPs示例应该仍然有效。

#3


6  

Draft C++11 standard http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf says about it (Alignment-specifier is of the form alignas ( assignment-expression )):

C++11标准:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf。(align-specifier是表单alignas(赋值表达式)):

7.6.2 Alignment specifier [dcl.align]

土壤质素对齐说明符(dcl.align)

1 An alignment-specifier may be applied to a variable or to a class data member, but it shall not be applied to a bit-field, a function parameter, the formal parameter of a catch clause (15.3), or a variable declared with the register storage class specifier. An alignment-specifier may also be applied to the declaration of a class or enumeration type. An alignment-specifier with an ellipsis is a pack expansion.

1可以对变量或类数据成员应用对齐说明符,但不能对位域、函数参数、catch子句(15.3)的形式参数或寄存器存储类说明符声明的变量应用。别名说明符也可以应用于类或枚举类型的声明。一个带有省略号的aligni -specifier是一个包扩展。

I found this original proposal http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1877.pdf , it says:

我在http://www.open- std.org/jtc1/sc22/wg21/docs/2005 /n1877.pdf中找到了这个原始建议:

The alignment-specifier does not become part of the type, but it is possible to create a class type with aligned member variable(s).

标识符不会成为类型的一部分,但是可以使用对齐的成员变量创建类类型。

with this example:

用这个例子:

// Wrong attempt: Listing 6)
typedef double align_by<0x10000> hwDoubleVector; // Error!
Void clear(hwDoubleVector &toClear, unsigned size);

Looks like it's illegal to use it with typedef.

看起来在typedef中使用它是非法的。

#4


-1  

Try:

试一试:

typedef float alignas(16) aligned_block[4];