Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applying alignas() to an entire struct in C

Tags:

c

c11

I expected it to be possible to apply alignas/_Alignas to an entire struct declaration, like this:

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

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

struct S s = { 0 };

but both gcc and clang reject the declaration:

(gcc 6.3)

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

(clang 3.8)

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

What gives? Note that both compilers accept this construct if I compile the file as C++, or if alignas is replaced with the equivalent GCC extension,

struct __attribute__((aligned(__alignof__(max_align_t)))) S {
  int field;
};

Also note that the other plausible placements of alignas,

alignas(max_align_t) struct S { ... };
struct S alignas(max_align_t) { ... };
struct S { ... } alignas(max_align_t);

also throw syntax errors (albeit different ones).

like image 401
zwol Avatar asked Oct 02 '17 01:10

zwol


2 Answers

C11 is not very clear on these things, but a consensus has emerged how this is to be interpreted. C17 will have some of this clarified. The idea of not allowing types to be aligned is that there should never be different alignment requirements for compatible types between compilation units. If you want to force the alignment of a struct type, you'd have to impose an alignment on the first member. By that you'd create an incompatible type.

The start of the "Constraint" section as voted by the committee reads:

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.

like image 101
Jens Gustedt Avatar answered Nov 19 '22 21:11

Jens Gustedt


With GCC 7.2.0 (compiled on macOS Sierra, running on macOS High Sierra), and also with GCC 6.3.0 on the same platform, and with Clang from XCode 9, I get:

$ 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.
$

It appears that these compilers only allow you to apply the _Alignas (or alignas) alignment specifier to a variable declaration, not to a type definition. Your code — the code which produces the error (warning converted to error) — attempts to apply the alignment to the type.

Note that putting alignas(max_align_t) betweeen struct and S clearly violates the standard. Putting it in other places does not seem to work unless there is actually a variable defined, despite the message hinting "place it after "struct" to apply attribute to type declaration". Thus, this code compiles because it defines variable s0. Omit s0 and it fails to compile.

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

ISO/IEC 9899:2011 — The C11 Standard

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.


Interpretation

These rules do not allow the alignment specifier between struct and its tag, or between structtag and the { … } structure definition (even if the GCC __attribute__ notation worked in such contexts).

The rules in §6.7.5 ¶2 do not self-evidently preclude the alignment specifier in a structure type definition, though other wording implies that it could be used with a structure member (inside the { … } section), or associated with a variable declaration or definition. However, the fact that an alignment specifier is not allowed in a typedef has implications that it shouldn't be allowed in a type definition either.

In the short term, you will, I think, have to accept that what you tried to do (attach the alignment specifier to the structure type declaration) doesn't work. You can consider whether it is worth looking for a GCC (or Clang) bug report, and if there is none, whether it is worth creating one. It is marginal, to my way of thinking, whether it is actually a bug, but I can't see anything in the quoted standard material that precludes what you attempted directly. However, if you can't apply alignment to a typedef, it also makes sense not to be able to apply it to a structure type declaration — which is why I consider it marginal (I wouldn't be surprised to find that any attempted bug report is rejected).

like image 5
Jonathan Leffler Avatar answered Nov 19 '22 19:11

Jonathan Leffler