将 alignas() 应用于 C 中的整个结构

Applying alignas() to an entire struct in C

我希望可以将 alignas/_Alignas 应用于整个结构声明,如下所示:

#include <stddef.h>
#include <stdalign.h>

struct alignas(max_align_t) S {
  int field;
};

struct S s = { 0 };

但是 gcc 和 clang 都拒绝声明:

(海湾合作委员会 6.3)

test.c:4:8: error: expected ‘{’ before ‘_Alignas’
 struct alignas(max_align_t) S {
        ^

(铿锵声 3.8)

test.c:4:1: error: declaration of anonymous struct must be a definition
struct alignas(max_align_t) S {
^

什么给了?请注意,如果我将文件编译为 C++,或者如果 alignas 被替换为等效的 GCC 扩展,

,则两个编译器都接受此构造
struct __attribute__((aligned(__alignof__(max_align_t)))) S {
  int field;
};

另请注意 alignas

的其他合理位置
alignas(max_align_t) struct S { ... };
struct S alignas(max_align_t) { ... };
struct S { ... } alignas(max_align_t);

也会抛出语法错误(尽管不同)。

使用 GCC 7.2.0(在 macOS Sierra 上编译,运行 在 macOS High Sierra 上编译),以及同一平台上的 GCC 6.3.0,以及来自 XCode 9 的 Clang,我得到:

$ cat align17.c
#include <stddef.h>
#include <stdalign.h>

alignas(max_align_t) struct S
{
    int field;
};                      // Line 7

struct S s = { 0 };

// Alternative

struct S1
{
    int field;
};

alignas(max_align_t) struct S1 s1 = { 1 };
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -c align17.c
align17.c:7:1: error: useless ‘_Alignas’ in empty declaration [-Werror]
 };
 ^
cc1: all warnings being treated as errors
$ clang -O3 -g -std=c11 -Wall -Wextra -Werror  -c align17.c
align17.c:4:1: error: attribute '_Alignas' is ignored, place it after "struct" to apply attribute to type
      declaration [-Werror,-Wignored-attributes]
alignas(max_align_t) struct S
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/9.0.0/include/stdalign.h:28:17: note: 
      expanded from macro 'alignas'
#define alignas _Alignas
                ^
1 error generated.
$

这些编译器似乎只允许您将 _Alignas(或 alignas对齐说明符 应用于变量声明,而不是类型定义。您的代码——产生错误的代码(警告转换为错误)——尝试将对齐应用于类型。

请注意,将 alignas(max_align_t) 放在 structS 之间显然违反了标准。将它放在其他地方似乎不起作用,除非实际上定义了一个变量,尽管消息提示 "place it after "struct" to apply attribute to type declaration"。因此,这段代码可以编译,因为它定义了变量 s0。省略 s0 编译失败。

struct S
{
    int field;
} alignas(max_align_t) s0;

ISO/IEC 9899:2011 — C11 标准

6.7 Declarations

Syntax

1 declaration:
        declaration-specifiers init-declarator-listopt ;
        static_assert-declaration

declaration-specifiers:
        storage-class-specifier declaration-specifiersopt
        type-specifier declaration-specifiersopt
        type-qualifier declaration-specifiersopt
        function-specifier declaration-specifiersopt
        alignment-specifier declaration-specifiersopt

6.7.2 Type specifiers

Syntax 1 type-specifier:
        void
        char
        short
        int
        long
        float
        double
        signed
        unsigned
        _Bool
        _Complex
        atomic-type-specifier
        struct-or-union-specifier
        enum-specifier
        typedef-name

6.7.2.1 Structure and union specifiers

Syntax

1 struct-or-union-specifier:
        struct-or-union identifieropt { struct-declaration-list }
        struct-or-union identifier

struct-or-union:
        struct
        union

6.7.5 Alignment specifier

Syntax

1 alignment-specifier:
        _Alignas ( type-name )
        _Alignas ( constant-expression )

Constraints

2 An alignment attribute shall not be specified in a declaration of a typedef, or a bit-field, or a function, or a parameter, or an object declared with the register storage-class specifier.

Semantics

6 The alignment requirement of the declared object or member is taken to be the specified alignment. An alignment specification of zero has no effect.141) When multiple alignment specifiers occur in a declaration, the effective alignment requirement is the strictest specified alignment.

7 If the definition of an object has an alignment specifier, any other declaration of that object shall either specify equivalent alignment or have no alignment specifier. If the definition of an object does not have an alignment specifier, any other declaration of that object shall also have no alignment specifier. If declarations of an object in different translation units have different alignment specifiers, the behavior is undefined.

141) An alignment specification of zero also does not affect other alignment specifications in the same declaration.


解读

这些规则不允许 struct 与其标记之间或 structtag 与 [=45] 之间的对齐说明符=] 结构定义(即使 GCC __attribute__ 符号在这种情况下有效)。

§6.7.5 ¶2 中的规则并没有不言而喻地排除结构类型定义中的对齐说明符,尽管其他措辞暗示它可以与结构成员一起使用(在 { … }部分),或与变量声明或定义相关联。但是,typedef 中不允许使用对齐说明符这一事实意味着它也不应该在类型定义中被允许。

在短期内,我认为您将不得不接受您尝试做的事情(将对齐说明符附加到结构类型声明)不起作用。您可以考虑是否值得寻找 GCC(或 Clang)错误报告,如果有 none,是否值得创建一个。以我的思维方式,它是否真的是一个错误是微不足道的,但我在引用的标准 material 中看不到任何排除你直接尝试的东西。然而,如果你不能将对齐应用到 typedef,那么不能将它应用到结构类型声明也是有意义的——这就是为什么我认为它是边缘的(我不会惊讶地发现任何尝试的错误报告被拒绝)。

C11 对这些事情不是很清楚,但已经形成了如何解释的共识。 C17 将对此进行一些澄清。不允许类型对齐的想法是编译单元之间的兼容类型永远不应该有不同的对齐要求。如果要强制 struct 类型对齐,则必须对第一个成员强制对齐。这样你就会创建一个不兼容的类型。

委员会投票决定的 "Constraint" 部分开头为:

An alignment specifier shall appear only in the declaration specifiers of a declaration, or in the specifier-qualifier list of a member declaration, or in the type name of a compound literal. An alignment specifier shall not be used in conjunction with either of the storage-class specifiers typedef or register, nor in a declaration of a function or bit-field.