C and C++ Alignment Compatibility

ISO/IEC JTC1 SC22 WG21 N3190 = 10-0180 - 2010-11-12

Lawrence Crowl (crowl@google.com, Lawrence@Crowl.org)
Daveed Vandevoorde (daveed@edg.com)

This paper revises

ISO/IEC JTC1 SC22 WG21 N3093 = 10-0083 - 2010-03-22

This revision

This revision has no effect on C compatibility.

Introduction
    Fundamental Alignment
        Proposal
    Alignof Operator
    Declaring Alignment
        Proposal
    Alignment Semantics
        Proposal
    Aligned Allocation
        Proposal
Proposed Wording for C++
    2.12 Keywords [lex.key]
    3.11 Alignment [basic.align]
    7.6.1 Attribute syntax and semantics [dcl.attr.grammar]
    7.6.2 Alignment attribute specifier [dcl.align]
    14.5.3 Variadic templates [temp.variadic]
    17.6.1.2 Headers [headers]
    18.1 General [support.general]
    18.10 Other runtime support [support.runtime]
    20.7.6.6 Other transformations [meta.trans.other]
    D.5 C standard library headers [depr.c.headers]

Introduction

The compatibility between the C and C++ alignment facilities is important to many members of the respective communities. This paper analyses the compatibility between the draft standards, WG14 N1425. and N3035, WG21 N3035. with respect to alignment.

This document presents C++-specific edits to what we believe to be the consensus proposal of the C and C++ compatibility mailing list. It incorporates revised wording for the C++ standards. We believe that no wording change is required for C and that full compatiblity has been maintained.

This document addresses national body comments GB 31 and (more generally) US 1.

Fundamental Alignment

Both languages have the same notion of fundamental alignment (<= alignof(max_align_t)) and extended alignment (> alignof(max_align_t)). Extended alignment support is implementation-defined in both languages.

Both languages intend to constrain the alignments to powers of two, but the wording to do so is confusing, and likely subject to misinterpretation. In particular, the 'weaker' constraint does not seem to be satisfiable unless the alignments are restricted to powers of two. Explicitly restricting alignment to powers of two would improve both languages.

Proposal

Explicitly constrain alignments to powers of two.

Alignof Operator

Both C and C++ define an alignof operator. These have compatible syntax and semantics:

unary-expression:
alignof ( type-name/id )

Neither language provides an alignof rule for expressions.

unary-expression:
alignof unary-expression

In both languages, the result is of type size_t, and the results are meaningfully comparable.

Declaring Alignment

It is in the declaration of alignment that C and C++ differ significantly.

C adds alignment-specifiers to its grammar.

declaration-specifiers:
alignment-specifier declaration-specifiersopt
alignment-specifier:
_Align ( type-name )
_Align ( constant-expression )

The original C++ proposal did essentially the same, but with a different keyword.

decl-specifier:
alignment-specifier
alignment-specifier:
alignas ( type-id )
alignas ( constant-expression )

However, the current C++ working draft uses attributes.

simple-declaration:
attribute-specifieropt declaration-specifiersopt attribute-specifieropt init-declarator-listopt ;

where the alignment attribute is one of:

attribute:
align ( type-name )
align ( assignment-expression )

and where the assignment-expression shall be an integral constant expression.

Proposal

Spell the C1x keyword as "_Alignas", and revert the C++ proposal to a keyword, but syntactically in the position of attributes.

attribute-specifier:
alignment-specifier
alignment-specifier:
alignas ( type-id ) ...opt
alignas ( constant-expression ) ...opt

Introduce a system header, <stdalign.h>, analagous to <stdbool.h>, that creates an identical spelling in both C and C++ for the keyword. Example:

#ifndef __cplusplus
#define alignas _Alignas
#define __alignas_is_defined 1
#endif

Alignment Semantics

Fortunately, C and C++ have very similar semantics for the effect of declaring alignment.

However, there are some differences.

Proposal

Define each individual alignment to zero to have no effect. That is, when there are multiple alignments specified, only alignments to zero have no effect.

A portable program cannot make use of relaxed alignment, so we propose that it remains disallowed in C and in C++.

Require that a definition or a tentative definition specifies the alignment; other declarations shall have the same alignment or no alignment.

Aligned Allocation

C defines an aligned_alloc function. C++ appears to add nothing for aligned allocation, though does leave some support implementation-defined.

Proposal

Defer this issue to the editor.

Proposed Wording for C++

These edits are relative to working draft WG21 N3092.

Note to the editor: Replace every occurrence of attribute-specifier with attribute-specifier-seq throughout the working draft except in 7.6.1 paragraphs 1, 3, and 6 (but including paragraph 4).

2.12 Keywords [lex.key]

Add the keyword alignas before the keyword alignof.

3.11 Alignment [basic.align]

Edit paragraph 1 as follows.

Object types have alignment requirements (3.9.1, 3.9.2) which place restrictions on the addresses at which an object of that type may be allocated. An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type; stricter alignment can be requested using the alignment attribute (7.6.2) alignment specifier ([dcl.align]).

Edit paragraph 4 as follows. Note the inserted comma.

Alignments are represented as values of the type std::size_t. Valid alignments include only those values returned by an alignof expression for the fundamental types plus an additional implementation-defined set of values, which may be empty. [Footnote: It is intended that every valid alignment value be an integral power of two. —end footnote] Every alignment value shall be a non-negative integral power of two.

7.6.1 Attribute syntax and semantics [dcl.attr.grammar]

Within paragraph 1, edit as follows:

attribute-specifier-seq:
attribute-specifier-seqopt attribute-specifier
attribute-specifier:
[ [ attribute-list ] ]
alignment-specifier
alignment-specifier:
alignas ( type-id ...opt)
alignas ( alignment-expression ...opt)

7.6.2 Alignment attribute specifier [dcl.align]

Edit the section heading as above.

Edit paragraph 1 as follows. Note that CWG 1036 also edits this paragraph. We see no semantic conflict.

The attribute-token align specifies alignment (3.11). The attribute shall have one of the following forms:

align ( type-id )
align ( assignment-expression )

The attribute may be followed by an ellipsis. The attribute An alignment-specifier may be applied to a variable that is neither a function parameter nor declared with the register register storage class specifier and to a class data member that is not a bit-field. The attribute An alignment-specifier may also be applied to the declaration of a class or enumeration type. An alignment-specifier with an ellipsis is a pack expansion ([temp.variadic]).

Edit within paragraph 2 as follows.

When the alignment attribute alignment-specifier is of the form alignas ( assignment-expression ):

Edit paragraph 3 as follows.

When the alignment attribute alignment-specifier is of the form alignas( type-id), it shall have the same effect as alignas(alignof(type-id)) ([expr.alignof]).

Edit paragraph 4 as follows.

When multiple alignment attributes alignment-specifiers are specified for an object, the alignment requirement shall be set to the strictest specified alignment.

Edit paragraph 5 as follows.

The combined effect of all alignment attributes alignment-specifiers in a declaration shall not specify an alignment that is less strict than the alignment that would otherwise be required for the object being declared.

Edit paragraph 6 as follows.

If the defining declaration of an entity has an alignment attribute alignment-specifier, any non-defining declaration of that entity shall either specify equivalent alignment or have no alignment attribute alignment-specifier. Conversely, if any declaration of an entity has an alignment attribute alignment-specifier, every defining declaration of that entity shall specify an equivalent alignment. No diagnostic is required if declarations of an entity have different alignment attribute alignment-specifiers in different translation units.

[Example:


// Translation unit #1:
struct S { int x; } s, p = &s;
// Translation unit #2:
struct [[align(16)]] S; // error: definition of S lacks alignment; no
struct alignas(16) S;   // error: definition of S lacks alignment; no
extern S* p;                 // diagnostic required

end example]

Edit paragraph 7 as follows.

[Example: An aligned buffer with an alignment requirement of A and holding N elements of type T other than char, signed char, or unsigned char can be declared as:


T buffer [[ align(T), align(A) ]] [N];
alignas(T) alignas(A) T buffer[N];

Specifying align(T) in the attribute-list alignas(T) ensures that the final requested alignment will not be weaker than alignof(T), and therefore the program will not be ill-formed. —end example]

Edit paragraph 8 as follows.

[Example:


void f [[ align(double) ]] (); // error: alignment applied to function
alignas(double) void f(); // error: alignment applied to function
unsigned char c
   [[ align(double) ]] [sizeof(double)];
alignas(double) unsigned char c[sizeof(double)];
            // array of characters, suitably aligned for a double
extern unsigned char c[sizeof(double)];
            // no alignas necessary
extern unsigned char c
   [[ align(float) ]] [sizeof(double)];
alignas(float) extern unsigned char c[sizeof(double)];
            // error: different alignment in declaration

end example]

14.5.3 Variadic templates [temp.variadic]

Edit within paragraph 4 as follows.

Edit paragraph 6 as follows.

The instantiation of an expansion produces a list E1 O E2 O ... O EN, where N is the number of elements in the pack expansion parameters and O is the syntactically-appropriate separator for the list (if any). Each Ei is generated by instantiating the pattern and replacing each pack expansion parameter with its ith element. All of the Ei become elements in the enclosing list. [Note: The variety of list varies with the context: expression-list, base-specifier-list, template-argument-list, etc. —end note]

17.6.1.2 Headers [headers]

Add <cstdalign> to "Table 14 — C++ headers for C library facilities".

18.1 General [support.general]

Add <cstdalign> to "Table 16 — Language support library summary" under "18.10 Other runtime support".

18.10 Other runtime support [support.runtime]

Add a new table after "Table 26 — Header <cstdbool> synopsis".

Table ?? — Header <cstdalign> synopsis".
Type Names(s)
Macro: __alignas_is_defined

Add a new paragraph after paragraph 6.

The header <cstdalign> and the header <stdalign.h> shall not define a macro named alignas.

20.7.6.6 Other transformations [meta.trans.other]

Edit within table 53 as follows.

Table 53 — Other transformations
TemplateConditionComments
template < std::size_t Len, std::size_t Align = default-alignment> struct aligned_storage; Len shall not be zero. Align shall be equal to alignof<T> for some type T or to default-alignment. The value of default-alignment shall be the most stringent alignment requirement for any C++ object type whose size is no greater than Len (3.9). The member typedef type shall be a POD type suitable for use as uninitialized storage for any object whose size is at most Len and whose alignment is a divisor of Align.
template < std::size_t Len, class ... Types > struct aligned_union; At least one type is provided. The member typedef type shall be a POD type suitable for use as uninitialized storage for any object whose type is listed in Types; its size shall be at least Len. The static member alignment_value shall be an integral constant of type std::size_t whose value is the strictest alignment of all types listed in Types.
... ... ...

Edit paragraph 1 as follows.

[Note: A typical implementation would define aligned_storage as:


template <std::size_t Len, std::size_t Alignment>
struct aligned_storage {
  typedef struct {
     unsigned char __data [[ align(Alignment) ]] [Len];
     alignas(Alignment) unsigned char __data[Len];
  } type;
};

end note]

D.5 C standard library headers [depr.c.headers]

Add <stdalign.h> to "Table 144 — C headers".