35

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

#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()可以和不可以放在哪里。

编辑(2013 年 4 月)

标准中的相关条款是 7.6.2,特别是 7.6.2.1

对齐说明符可以应用于变量或类数据成员,但不应应用于位字段、函数参数、catch 子句(15.3)的形式参数或用注册存储类说明符。对齐说明符也可以应用于类或枚举类型的声明。带有省略号的对齐说明符是包扩展 (14.5.3)。

正如 Red XIII 已经挖掘出来的那样。但是,我不够专业,不知道这对我上面的测试意味着什么。

如果 clang 接受我的属性这一事实意味着什么,那么也许值得一提的是,当尝试使用using指令而不是 atypedef时,clang 也会抱怨。此外,与此问题早期版本中的声明相反,gcc 不仅警告,而且确实忽略了我对对齐的愿望。

4

4 回答 4

33

我认为您只是将其放置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 typedef-name也可以由alias -declaration引入。关键字后面的标识符成为usingtypedef -name,标识符后面的可选属性说明序列属于该typedef-name。它具有与由说明符引入的语义相同的语义typedef。[...]

(强调我的)

上面的内容很清楚using,规则typedef分布在几个段落中,包括在 §8.3/1 的末尾,您可以在其中找到:

8.3 声明符的含义[dcl.meaning]

1 [...]声明符 id后面的可选属性说明符 序列属于声明的实体。

(再次强调我的)


更新:上述答案集中在必须alignas放置的位置,而不是其确切含义。再想一想,还是觉得上面说的应该是成立的。考虑:

7.6.2 对齐说明符 [dcl.align]

1对齐说明可应用于变量或类数据成员,但不应应用于位字段、函数参数、异常声明(15.3) 或使用register存储类声明的变量说明符。对齐说明也可以应用于类的声明或定义(分别在详细类型说明符(7.1.6.3)或类头(第 9 条)中)以及枚举的声明或定义(分别在opaque-enum-declarationenum-head中(7.2))。带有省略号的对齐说明符是包扩展 (14.5.3)。

它列出了可以明确应用的情况,列出了明显不能应用的情况。上述问题的例子都不是。

也有人可能会争辩说,类型别名由创建typedefusing携带对齐规范作为别名类型的一部分。此别名可用于创建 7.6.2p1 允许的变量等,但不能使用register等创建变量。

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

于 2013-04-09T20:48:33.720 回答
14

您不能将对齐应用到typedef. 在对齐说明符的 C++ 模型中,对齐是类型本身不可分割的一部分,并且 atypedef不会创建新类型(它只是为现有类型提供新名称)因此在中应用对齐说明符没有意义一份typedef声明。

[dcl.align] (7.6.2)p1

对齐说明可以应用于变量或类数据成员[...]。对齐说明也可以应用于类的声明或定义(分别在详细类型说明符(7.1.6.3)或类头(第 9 条)中)以及枚举的声明或定义(分别在opaque-enum-declarationenum-head中(7.2))。

这些是标准规定可以应用对齐说明符( )的唯一地方。alignas(...)请注意,这包括typedef声明或alias-declaration

根据[dcl.attr.grammar] (7.6.1)p4

如果属于某个实体或语句的属性说明符序列包含不允许应用于该实体或语句的属性,则该程序是非良构的。

此措辞旨在适用于alignas以及可能出现在属性说明符序列中的其他形式的属性,但是当对齐从“真实”属性切换为不同类型的属性说明符时未正确更新-seq

所以:您使用的示例代码alignas应该格式错误的。C++ 标准目前没有明确说明这一点,但它也不允许使用,因此它目前会导致未定义的行为(因为标准没有为它定义任何行为)。

于 2015-11-30T19:44:27.863 回答
8

C++ 11 标准草案http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf对此进行了说明(对齐说明符的形式为alignas(赋值表达式)) :

7.6.2 对齐说明符 [dcl.align]

1 对齐说明符可应用于变量或类数据成员,但不得应用于位字段、函数参数、catch 子句(15.3)的形式参数或用寄存器存储类说明符。对齐说明符也可以应用于类或枚举类型的声明。带有省略号的对齐说明符是包展开。

我找到了这个原始提案http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1877.pdf,它说:

对齐说明符不会成为类型的一部分,但可以创建具有对齐成员变量的类类型。

用这个例子:

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

看起来与它一起使用是非法的typedef

于 2013-04-03T15:35:00.223 回答
-1

尝试:

typedef float alignas(16) aligned_block[4];
于 2013-04-03T16:27:43.183 回答