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).
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
orregister
, nor in a declaration of a function or bit-field.
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;
6.7 Declarations
Syntax
1 declaration:
declaration-specifiers init-declarator-listopt;
static_assert-declarationdeclaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
function-specifier declaration-specifiersopt
alignment-specifier declaration-specifiersopt6.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-name6.7.2.1 Structure and union specifiers
Syntax
1 struct-or-union-specifier:
struct-or-union identifieropt{
struct-declaration-list}
struct-or-union identifierstruct-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.
These rules do not allow the alignment specifier between struct
and its tag, or between struct
tag
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With