为了使我的代码标准化并使其更具可移植性,我更换了
#ifdef __GNUC__
typedef __attribute__((aligned(16))) float aligned_block[4];
#else
typedef __declspec(align(16)) float aligned_block[4];
#endif
与
typedef float alignas(16) aligned_block[4];
在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
而clang 3.2没有警告(即使-Weverything -Wno-c++98-compat -pedantic
)。
所以我想知道上面的代码是否正确,更一般地说,alignas()
可以放在哪里也不能放置。
EDIT(2013年4月) :
该标准的相关文章是7.6.2,特别是7.6.2.1
已经被Red XIII挖出来了。但是,我不够专业,不知道这对我上面的测试意味着什么。对齐 - 说明符可以应用于变量或类数据成员,但不应用于位字段,函数参数,catch子句的形式参数(15.3)或变量使用寄存器存储类说明符声明。对齐说明符也可以应用于类或枚举类型的声明。带省略号的对齐说明符是包扩展(14.5.3)。
如果clang接受我的属性这一事实意味着什么,或许值得一提的是,当尝试使用using
指令而不是typedef
时,clang也会抱怨。此外,与此问题的早期版本中的陈述相反,gcc不仅警告,而且实际上忽略了我对齐的愿望。
答案 0 :(得分:26)
我认为你刚刚将alignas
置于错误的位置。如果你在标识符后直接移动,GCC和Clang都很高兴并应用对齐方式:
typedef float aligned_block alignas(16) [4];
typedef float aligned_block [4] alignas(16);
如果使用using
,情况也会如此,差异也会变得更明显。以下是GCC接受不的两个版本(忽略警告,对齐):
using aligned_block = float alignas(16)[4];
using aligned_block = float[4] alignas(16);
这是接受的:
using aligned_block alignas(16) = float[4];
我认为GCC适用
7.1.3 typedef说明符[dcl.typedef]
2 alde-name 也可以通过 alias-declaration 引入。
using
关键字后面的标识符成为 typedef-name ,可选属性说明符-seq 位于< em> identifier 附属于 typedef-name 。它具有与typedef
说明符引入的语义相同的语义。 [...]
(强调我的)
以上对using
非常清楚,typedef
的规则分散在几个段落中,包括§8.3/ 1的末尾,您可以找到:
8.3声明者的意义[dcl.meaning]
1 [...] declarator-id appertains之后的可选 attribute-specifier-seq 到声明的实体。
(再次强调我的)
更新:以上答案主要集中在 alignas
必须放置,而不是其确切含义。在考虑了一些之后,我仍然认为上述内容应该是有效的。考虑:
7.6.2对齐说明[dcl.align]
1 alignment-specifier 可以应用于变量或类数据成员,但不应用于位字段,函数参数, exception-declaration (15.3),或使用
register
存储类说明符声明的变量。 alignment-specifier 也可以应用于类的声明或定义(在 elaborated-type-specifier (7.1.6.3)或 class-head中(第9条),以及枚举的声明或定义(分别在 opaque-enum-declaration 或 enum-head 中)(7.2) ))。带有省略号的 alignment-specifier 是包扩展(14.5.3)。
它列出了可以明确应用的情况,并列出了明显无法 应用的情况。以上问题的例子都不是。
还可以说,typedef
或using
创建的类型别名将对齐规范作为别名类型的一部分。此别名可用于创建7.6.2p1允许的变量等,但不能用register
等创建变量。
从这个意义上说,我认为属性说明符是以延迟的方式应用(在7.6.2的意义上),因此当对齐规范放在语法正确的位置时,OPs示例应该仍然有效。
答案 1 :(得分:11)
您无法将对齐应用于typedef
。在对齐说明符的C ++模型中,对齐是类型本身不可分割的一部分,而typedef
不会创建新类型(它只为现有类型提供新名称),因此它没有意义在typedef
声明中应用对齐说明符。
来自 [dcl.align](7.6.2)p1 :
alignment-specifier 可以应用于变量或类数据成员[...]。 alignment-specifier 也可以应用于类的声明或定义(在 elaborated-type-specifier (7.1.6.3)或 class-head中(第9条),以及枚举的声明或定义(在 opaque-enum-declaration 中) 或 enum-head ,分别为(7.2))。
这些是标准中可以应用 alignment-specifier (alignas(...)
)的唯一地方。请注意,此不包含typedef
声明,也不包含 alias-declaration 。
每 [dcl.attr.grammar](7.6.1)p4 :
如果属于某个实体或语句的 attribute-specifier-seq 包含不允许应用于该实体或语句的属性,则程序生病-formed。
此措辞旨在适用于alignas
以及可能出现在属性说明符-seq 中的其他形式的属性,但在对齐切换时未正确更新作为另一种 attribute-specifier-seq 的“真实”属性。
所以:使用alignas
的示例代码假设是错误的。 C ++标准目前没有明确说明这一点,但它也不允许使用,因此它当前会导致未定义的行为(因为标准没有为它定义任何行为)。
答案 2 :(得分:7)
草案C ++ 11标准http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf说明了它(Alignment-speci fi er的形式为alignas
(赋值表达式)):
7.6.2对齐指示符[dcl.align]
1对齐规范可以应用于变量或类数据成员,但不应用 到一个位域,一个函数参数,一个catch子句的形式参数(15.3),或一个声明的变量 与寄存器存储类指定。对齐指定器也可以应用于声明 类或枚举类型。具有省略号的对齐规范是包扩展。
我找到了这个原始提案http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1877.pdf,它说:
alignment-specifier不会成为类型的一部分,但可以创建类类型 对齐成员变量。
这个例子:
// Wrong attempt: Listing 6)
typedef double align_by<0x10000> hwDoubleVector; // Error!
Void clear(hwDoubleVector &toClear, unsigned size);
将它与typedef
一起使用似乎是违法的。
答案 3 :(得分:-1)
尝试:
typedef float alignas(16) aligned_block[4];