0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

6.7 Declarations, CN3054:2022 (9) p96.c

Last updated at Posted at 2022-10-21

はじめに(Introduction)

N3054 Working Draft, Standard for Programming Language C

C++ nは、ISO/IEC JTC1 SC22 WG14の作業原案(Working Draft)です。
公式のISO/IEC 9899原本ではありません。

ISO/IEC JTC1 SC22 のWG14を含むいくつかのWGでは、可能な限り作業文書を公開し、幅広い意見を求めています。

ISO/IEC JTC1 SC7からISO/IEC JTC1 SC22リエゾンとして、2000年頃、C/C++の品質向上に貢献しようとした活動をしていたことがあります。その頃は、まだISO/IEC TS 17961の原案が出る前です。Cの精神が優勢で、セキュリティ対策は補助的な位置付けでした。ISO/IEC TS 17961の制定と、C/C++のライブラリ類の見直しと、C++の進化はどんどん進んでいきます。 

進化の具合が、どちらに行こうとしているかは、コンパイルて実行させてみないとわかりません。C/C++の規格案の電子ファイルは、そのままコンパイルできる形式であるとよいと主張してきました。MISRA-C/C++, CERTC/C++でも同様です。MISRA-C/C++は、Example Suiteという形で、コード断片をコンパイルできる形で提供するようになりました。

一連の記事はコード断片をコンパイルできる形にする方法を検討してコンパイル、リンク、実行して、規格案の原文と処理系(gcc, clang)との違いを確認し、技術内容を検討し、ISO/IEC JTC1 SC22 WG21にフィードバックするために用います。
また、CERT C/C++, MISRA C/C++等のコーディング標準のコード断片をコンパイルする際の参考にさせていただこうと考えています。CERT C++, MISRA C++が標準化の動きとの時間的なずれがあれば確認できれば幸いです。また、boostライブラリとの関連、Linux OS, 箱庭プロジェクト、g++(GCC), clang++(LLVM)との関係も調査中です。
何か、抜け漏れ、耳より情報がありましたらおしらせくださると幸いです。

背景(back ground)

C/C++でコンパイルエラーが出ると、途方にくれることがしばしばあります。
何回かに1回は、該当するエラーが検索できます。
ただ、条件が違っていて、そこでの修正方法では目的を達成しないこともしばしばです。いろいろな条件のコンパイルエラーとその対応方法について、広く記録することによって、いつか同じエラーに遭遇した時にやくに立つことを目指しています。

過去に何度か、自分のネットでの記録に助けられたことがあります。

また
https://researchmap.jp/joub9b3my-1797580/#_1797580
に記載したサイトのお世話になっています。

作業方針(sequence)

clangでは--std=c11, -std=C17 -std=c2xの3種類
gccでは-std=c11, -std=C17 -std=c2xの3種類
でコンパイルし、

1)コンパイルエラーを収集する。
2)コンパイルエラーをなくす方法を検討する。
コンパイルエラーになる例を示すだけが目的のコードは、コンパイルエラーをなくすのではなく、コンパイルエラーの種類を収集するだけにする。
文法を示すのが目的のコード場合に、コンパイルエラーをなくすのに手間がかかる場合は、順次作業します。
3)リンクエラーをなくす方法を検討する。
文法を示すのが目的のコード場合に、リンクエラーをなくすのに手間がかかる場合は、順次作業します。
4)意味のある出力を作る。
コンパイル、リンクが通っても、意味のある出力を示そうとすると、コンパイル・リンクエラーが出て収拾できそうにない場合がある。順次作業します。

1)だけのものから4)まで進んだものと色々ある状態です。一歩でも前に進むご助言をお待ちしています。「検討事項」の欄に現状を記録するようにしています。

bash
$ docker run -v /Users/ogawakiyoshi/n4910/n3540:/Users/ogawakiyoshi/n4910/n3540 -it kaizenjapan/n3540 /bin/bash

読書感想文

CコンパイラによるC言語規格の読書感想文として掲載しています。

コンパイル実験が、CN3242に対する、gccとclangによる感想文だということご理解いただけると幸いです。

読書感想文は人間かAIだけが作るものとは限りません。
本(電子書籍を含む)を入力として、その内容に対する文字列を読書感想文として受け止めましょう。
元の文章をあり方、コンパイルできるように電子化しておくこと、コンパイラが解釈可能な断片の作り方など。

個人開発

Cコンパイラの試験を一人でもくもくとやっているのは個人開発の一つの姿です。

<この項は書きかけです。順次追記します。>

編纂器(Compiler)

clang --version

Debian clang version 14.0.6-++20220622053050+f28c006a5895-1~exp1~20220622173135.152
Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin

gcc --version

gcc (GCC) 12.1.0 Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

6.7 Declarations, CN3054:2022 (9) p96.c

算譜(source code)

p96.c
// CN3054 Committee Draft, Standard for Programming Language C
// http://www.open-std.org/jtc1/sc22/wg14/docs/papers/2022/n3054.pdf
const char * n3054 = "6.7 Declarations, CN3054:2022 (9) p96.c";
// Debian clang version 14.0.5-++20220610033153+c12386ae247c-
// g++ (GCC) 12.1.0 Copyright (C) 2022 Free Software Foundation, Inc.
// Edited by Dr. OGAWA Kiyoshi. Compile procedure and results record.
// C++N3054:2022 Standard Working Draft on ISO/IEC 14882(0) sample code compile list

#include "N3054.h"

// 6.7 Declarations
// Syntax
//  declaration:
/* declaration-specifiers init-declarator-listopt ; 
attribute-specifier-sequence declaration-specifiers init-declarator-list ; static_assert-declaration
attribute-declaration
declaration-specifiers:
declaration-specifier attribute-specifier-sequenceopt
declaration-specifier declaration-specifiers declaration-specifier:
init-declarator-list:
init-declarator:
storage-class-specifier type-specifier-qualifier function-specifier
init-declarator
init-declarator-list , init-declarator
declarator
declarator = initializer
attribute-declaration:
attribute-specifier-sequence ;*/
// Constraints
//  A declaration other than a static_assert or attribute declaration shall declare at least a declarator (other than the parameters of a function or the members of a structure or union), a tag, or the members of an enumeration.
//  If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except that:
// — a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type;
// — enumeration constants and tags may be redeclared as specified in 6.7.2.2 and // 6.7.2.3, respec- tively.
//  All declarations in the same scope that refer to the same object or function shall specify compatible types.
// In an underspecified declaration all declared identifiers that do not have a prior declaration shall be ordinary identifiers.
Semantics
//  A declaration specifies the interpretation and properties of a set of identifiers. A definition of an identifier is a declaration for that identifier that for:
// — an object, causes storage to be reserved for that object,
// — a function, includes the function body137),
// — an enumeration constant, is the only declaration of the identifier, or — a typedef name, is the first (or only) declaration of the identifier.
// 137)Function definitions have a different syntax, described in 6.9.1.
//  The declaration specifiers consist of a sequence of specifiers, followed by an optional attribute specifier sequence. The declaration specifiers indicate the linkage, storage duration, and part of the type of the entities that the declarators denote. The init declarator list is a comma-separated sequence of declarators, each of which may have additional type information, or an initializer, or both. The declarators contain the identifiers (if any) being declared. The optional attribute specifier sequence in a declaration appertains to each of the entities declared by the declarators of the init declarator list.
//  If an identifier for an object is declared with no linkage, the type for the object shall be complete by the end of its declarator, or by the end of its init-declarator if it has an initializer. In the case of function parameters, it is the adjusted type (see 6.7.6.3) that is required to be complete.
//  The optional attribute specifier sequence terminating a sequence of declaration specifiers appertains to the type determined by the preceding sequence of declaration specifiers. The attribute specifier sequence affects the type only for the declaration it appears in, not other declarations involving the same type.
//  Except where specified otherwise, the meaning of an attribute declaration is implementation-defined.
//  EXAMPLE In the declaration for an entity, attributes appertaining to that entity may appear at the start of the declaration and after the identifier for that declaration.
[[deprecated]] void f [[deprecated]] (void); // valid
//  A declaration such that the declaration specifiers contain no type specifier or that is declared with constexpr is said to be underspecified. If such a declaration is not a definition, if it declares no or more than one ordinary identifier, if the declared identifier already has a declaration in the same scope, or if the declared entity is not an object, the behavior is undefined.
// Forward references: declarators (6.7.6), enumeration specifiers (6.7.2.2), initialization (6.7.10), type names (6.7.7), type qualifiers (6.7.3).
// 6.7.1 Storage-class specifiers
// Syntax
//  storage-class-specifier: auto
                   constexpr
                   extern
                   register
                   static
                   thread_local
                   typedef
// Constraints
//  At most, one storage-class specifier may be given in the declaration specifiers in a declaration, except that:
// — thread_local may appear with static or extern,
// — auto may appear with all the others except typedef138), and — constexpr may appear with auto, register, or static.
//  In the declaration of an object with block scope, if the declaration specifiers include thread_local, they shall also include either static or extern. If thread_local appears in any declaration of an object, it shall be present in every declaration of that object.
138)See "future language directions" (6.11.5).
// thread_local shall not appear in the declaration specifiers of a function declaration. auto shall only appear in the declaration specifiers of an identifier with file scope or along with other storage class specifiers if the type is to be inferred from an initializer.
//  An object declared with storage-class specifier constexpr or any of its members, even recursively, shall not have an atomic type, or a variably modified type, or a type that is volatile or restrict qualified. The declaration shall be a definition and shall have an initializer.139) The value of any constant expressions or of any character in a string literal of the initializer shall be exactly representable in the corresponding target type; no change of value shall be applied140). If an object
or subobject declared with storage-class specifier constexpr has pointer, integer, or arithmetic type, the implicit or explicit initializer value for it shall be a null pointer constant141), an integer constant expression, or an arithmetic constant expression, respectively.
// Semantics
//  Storage-class specifiers specify various properties of identifiers and declared features:
// — storage duration (static in block scope, thread_local, auto, register), — linkage (extern, static and constexpr in file scope, typedef),
// — value (constexpr), and
// — type (typedef).
//  The meanings of the various linkages and storage durations were discussed in 6.2.2 and 6.2.4, typedef is discussed in 6.7.8, and type inference using auto is discussed in 6.7.9.
//  A declaration of an identifier for an object with storage-class specifier register suggests that access to the object be as fast as possible. The extent to which such suggestions are effective is implementation-defined142) .
//  The declaration of an identifier for a function that has block scope shall have no explicit storage-class specifier other than extern.
//  If an aggregate or union object is declared with a storage-class specifier other than typedef, the properties resulting from the storage-class specifier, except with respect to linkage, also apply to the members of the object, including recursively for any aggregate or union member objects.
//  If auto appears with another storage-class specifier, or if it appears in a declaration at file scope, it is ignored for the purposes of determining a storage duration or linkage. In this case, it indicates only that the declared type may be inferred.
//  An object declared with a storage-class specifier constexpr has its value permanently fixed at translation-time; if not yet present, a const-qualification is implicitly added to the object’s type. The declared identifier is considered a constant expression of the respective kind, see 6.6.
//  NOTE 1 An object declared in block scope with a storage-class specifier constexpr and without static has automatic storage duration, the identifier has no linkage, and each instance of the object has a unique address obtainable with & (if it is not declared with the register specifier), if any. Such an object in file scope has static storage duration, the corresponding identifier has internal linkage, and each translation unit that sees the same textual definition implements a separate object with a distinct address.
//  NOTE 2 The constraints for constexpr objects are intended to enforce checks for portability at translation time.
139)All assignment expressions of such an initializer, if any, are constant expressions or string literals, see 6.7.10.
140)In the context of arithmetic conversions, 6.3.1 describes the details of changes of value that occur if values of arithmetic expressions are stored in the objects that for example have a different signedness, excess precision or quantum exponent. Whenever such a change of value is necessary, the constraint is violated.
// 141)The named constant or compound literal constant corresponding to an object declared with storage-class specifier constexpr and pointer type is a constant expression with a value null, and thus a null pointer and an address constant. However, even if it has type void* it is not a null pointer constant.
// 142)The implementation can treat any register declaration simply as an auto declaration. However, whether or not addressable storage is used, the address of any part of an object declared with storage-class specifier register cannot be computed, either explicitly (by use of the unary & operator as discussed in 6.5.3.2) or implicitly (by converting an array name to a pointer as discussed in 6.3.2.1). Thus, the only operator that can be applied to an array declared with storage-class specifier register is sizeof and the typeof operators.
         constexpr unsigned int minusOne constexpr unsigned int uint_max constexpr char string[]
constexpr unsigned char unstring[]
constexpr char8_t u8string[] constexpr double onethird
constexpr double onethirdtrunc constexpr _Decimal32 small
= -1;
= -1U;
= { "\xFF", };
= { "\xFF", };
= { u8"\xFF", };
= 1.0/3.0;
= (double)(1.0/3.0); = DEC64_TRUE_MIN * 0;
// constraint violation
// ok
// ok
// possible constraint
// violation
// ok
// possible constraint
// violation
// ok
// constraint violation
//                                         Using an octal or hexadecimal escape character sequence with a value greater than the largest representable value of the target character type (such as for unstring) possibly violates a constraint. Equally, an implementation that uses excess precision for floating constants violates the constraint for onethird; a diagnostic is required if a truncation of the mantissa occurs. In contrast to that, the explicit conversion in the initializer for onethirdtrunc ensures that the definition is valid. Similarly, the initializer of small has a quantum exponent that is larger than the largest possible quantum exponent for _Decimal32.
//  EXAMPLE 1 An identifier declared with the constexpr specifier may have its value used in constant expressions:
//  EXAMPLE 2 An object declared with the constexpr specifier stores the exact value of its initializer, no implicit value change is applied:
         constexpr int K = 47; enum {
      A = K,              // valid, constant initialization
};
constexpr int L = K; // valid, constexpr initialization static int b = K + 1; // valid, static initialization int array[K]; // not a VLA
                                   #include <float.h>
constexpr int A = 42LL;
constexpr signed short B = ULLONG_MAX; constexpr float C = 47u;
#if FLT_MANT_DIG > 24 constexpr float D = 536900000;
#endif
// valid, 42 always fits in an int
// constraint violation, value never
// fits
// valid, exactly representable
// in single precision
// constraint violation if float is
// 32-bit single-precision IEC 60559
#if (FLT_MANT_DIG == DBL_MANT_DIG) && (0 <= FLT_EVAL_METHOD) && (FLT_EVAL_METHOD <= 1)
constexpr float E = 1.0 / 3.0;
#endif
#if FLT_EVAL_METHOD == 0
constexpr float F = 1.0f / 3.0f;
#else
constexpr float F = (float)(1.0f / 3.0f);
// only valid if double expressions
// and float objects have the same
// precision
// valid, same type and precision
// needs cast to truncate the
// excess precision
#endif
//  EXAMPLE 3 This recursively applies to initializers for all elements of an aggregate object declared with the constexpr specifier:
// type-specifier:
// Except where the type is inferred (6.7.9), at least one type specifier shall be given in the declaration specifiers in each declaration, and in the specifier-qualifier list in each member declaration and type name. Each list of type specifiers shall be one of the following multisets (delimited by commas, when there is more than one multiset per item); the type specifiers may occur in any order, possibly intermixed with the other declaration specifiers.
// — void
// — char
// — signed char
// — unsigned char
// — short, signed short, short int, or signed short int
// — unsigned short, or unsigned short int
        constexpr static unsigned short array[] = {
3000, // valid, fits in unsigned short range
300000, // constraint violation if short is 16-bit
-1 // constraint violation, target type is unsigned
            };
struct S {
int x, y;
};
constexpr struct S s = {
               .x = INT_MAX, .y = UINT_MAX,
// valid
// constraint violation
         };
    Forward references: type definitions (6.7.8), type definitions (6.7.9).
// 6.7.2 Type specifiers Syntax
// Constraints
/*void
char
short
int
long
float
double
signed
unsigned
_BitInt ( constant-expression ) bool
_Complex _Decimal32 _Decimal64 _Decimal128 atomic-type-specifier struct-or-union-specifier enum-specifier typedef-name typeof-specifier
— int, signed, or signed int
— unsigned, or unsigned int
— long, signed long, long int, or signed long int
— unsigned long, or unsigned long int
— long long, signed long long, long long int, or signed long long int — unsigned long long, or unsigned long long int
— _BitInt( constant-expression), or signed _BitInt( constant-expression)
— unsigned _BitInt( constant-expression)
— float
— double
— long double
— _Decimal32
— _Decimal64
— _Decimal128
— bool
— float _Complex
— double _Complex
— long double _Complex
— atomic type specifier
— struct or union specifier
— enum specifier
— typedef name
— typeof specifier */
//  The type specifier _Complex shall not be used if the implementation does not support complex types, and the type specifiers _Decimal32, _Decimal64, and _Decimal128 shall not be used if the implementation does not support decimal floating types (see 6.10.9.3).
//  The parenthesized constant expression that follows the _BitInt keyword shall be an integer constant expression N that specifies the width (6.2.6.2) of the type. The value of N for unsigned _BitInt shall be greater than or equal to 1. The value of N for _BitInt shall be greater than or equal to 2. The value of N shall be less than or equal to the value of BITINT_MAXWIDTH (see 5.2.4.2.1).
// Semantics
//  Specifiers for structures, unions, enumerations, atomic types, and typeof specifiers are discussed in 6.7.2.1 through 6.7.2.5. Declarations of typedef names are discussed in 6.7.8. The characteristics of the other types are discussed in 6.2.5.
// For a declaration such that the declaration specifiers contain no type specifier a mechanism to infer the type from an initializer is discussed in 6.7.9. In such a declaration, optional elements, if any, of a sequence of declaration specifiers appertain to the inferred type (for qualifiers and attribute specifiers) or to the declared objects (for alignment specifiers).
//  Each of the comma-separated multisets designates the same type, except that for bit-fields, it is implementation-definedwhetherthespecifierintdesignatesthesametypeassigned intorthe sametypeasunsigned int.
Forward references: atomic type specifiers (6.7.2.4), enumeration specifiers (6.7.2.2), structure and union specifiers (6.7.2.1), tags (6.7.2.3), type definitions (6.7.8).
// 6.7.2.1 Structure and union specifiers
// Syntax
//  struct-or-union-specifier:
/*struct-or-union attribute-specifier-sequenceopt identifieropt { member-declaration-list }
struct-or-union:
struct-or-union attribute-specifier-sequenceopt identifier struct
union
member-declaration-list: member-declaration
member-declaration-list member-declaration
member-declaration:
attribute-specifier-sequenceopt specifier-qualifier-list member-declarator-listopt ; static_assert-declaration
specifier-qualifier-list:
type-specifier-qualifier attribute-specifier-sequenceopt
type-specifier-qualifier specifier-qualifier-list
type-specifier-qualifier: type-specifier
type-qualifier alignment-specifier
member-declarator-list: member-declarator
member-declarator-list , member-declarator
member-declarator: declarator
declaratoropt : constant-expression */
// Constraints
//  A member declaration that does not declare an anonymous structure or anonymous union shall contain a member declarator list.
//  A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.
//  The expression that specifies the width of a bit-field shall be an integer constant expression with a nonnegative value that does not exceed the width of an object of the type that would be specified were the colon and expression omitted143). If the value is zero, the declaration shall have no declarator.
//  Abit-fieldshallhaveatypethatisaqualifiedorunqualifiedversionofbool,signed int,unsigned 143)While the number of bits in a bool object is at least CHAR_BIT, the width of a bool is just 1 bit. int, a bit-precise integer type, or other implementation-defined type. It is implementation-defined
whether atomic types are permitted.
//  An attribute specifier sequence shall not appear in a struct-or-union specifier without a member declaration list, except in a declaration of the form:
struct-or-union attribute-specifier-sequence identifier ;
The attributes in the attribute specifier sequence, if any, are thereafter considered attributes of the
struct or union whenever it is named. Semantics
//  As discussed in 6.2.5, a structure is a type consisting of a sequence of members, whose storage is allocated in an ordered sequence, and a union is a type consisting of a sequence of members whose storage overlap.
//  Structure and union specifiers have the same form. The keywords struct and union indicate that the type being specified is, respectively, a structure type or a union type.
//  The optional attribute specifier sequence in a struct-or-union specifier appertains to the structure or union type being declared. The optional attribute specifier sequence in a member declaration appertains to each of the members declared by the member declarator list; it shall not appear if the optional member declarator list is omitted. The optional attribute specifier sequence in a specifier qualifier list appertains to the type denoted by the preceding type specifier qualifiers. The attribute specifier sequence affects the type only for the member declaration or type name it appears in, not other types or declarations involving the same type.
//  The member declaration list is a sequence of declarations for the members of the structure or union. If the member declaration list does not contain any named members, either directly or via an anonymous structure or anonymous union, the behavior is undefined144).
//  A member of a structure or union may have any complete object type other than a variably modified type.145) In addition, a member may be declared to consist of a specified number of bits (including a sign bit, if any). Such a member is called a bit-field 146); its width is preceded by a colon.
//  A bit-field is interpreted as having a signed or unsigned integer type consisting of the specified number of bits147). If the value 0 or 1 is stored into a nonzero-width bit-field of type bool, the value of the bit-field shall compare equal to the value stored; a bool bit-field has the semantics of a bool.
//  An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.
//  A bit-field declaration with no declarator, but only a colon and a width, indicates an unnamed bit-field.148) As a special case, a bit-field structure member with a width of zero indicates that no further bit-field is to be packed into the unit in which the previous bit-field, if any, was placed.
// An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure; an unnamed member whose type specifier is a union specifier with no tag is called an anonymous union. The members of an anonymous structure or union are members of the containing structure or union, keeping their structure or union layout. This applies recursively if the containing structure or union is also anonymous.
// 144)For further rules affecting compatibility and completeness of structure or union types, see 6.2.7 and 6.7.2.3.
// 145)A structure or union cannot contain a member with a variably modified type because member names are not ordinary identifiers as defined in 6.2.3.
146)The unary & (address-of) operator cannot be applied to a bit-field object; thus, there are no pointers to or arrays of bit-field objects.
// 147)As specified in 6.7.2 above, if the actual type specifier used is int or a typedef-name defined as int, then it is implementation-defined whether the bit-field is signed or unsigned. This includes an int type specifier produced us- ing the typeof specifiers (6.7.2.5).
148)An unnamed bit-field structure member is useful for padding to conform to externally imposed layouts.
//  Each non-bit-field member of a structure or union object is aligned in an implementation-defined
manner appropriate to its type.
//  Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.
//  The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit-field, then to the unit in which it resides), and vice versa. The members of a union object overlap in such a way that pointers to them when converted to pointers to character type point to the same byte. There may be unnamed padding at the end of a union object, but not at its beginning.
//  There may be unnamed padding at the end of a structure or union.
//  As a special case, the last member of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply. However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.
//  EXAMPLE 1 The following declarations illustrate the behavior when an attribute is written on a tag declaration:
//  EXAMPLE 2 The following illustrates anonymous structures and unions:
        struct [[deprecated]] S; // valid, [[deprecated]] appertains to struct S
   void f(struct S *s); struct S {
int a;
void g(struct [[deprecated]] S s); // invalid
// valid, the struct S type has the [[deprecated]]
// attribute
// valid, struct S inherits the [[deprecated]] attribute
         // from the previous declaration
   };
               struct v {
union { // anonymous union
struct { int i, j; }; // anonymous structure struct { long k, l; } w;
};
int m; } v1;
v1.i = 2; // valid
v1.k = 3; // invalid: inner structure is not anonymous v1.w.k = 5; // valid
                                  23 EXAMPLE 3 After the declaration:
struct s { int n; double d[]; };
thestructurestruct shasaflexiblearraymemberd.Atypicalwaytousethisis:
     int m = /* some value */;
struct s *p = malloc(sizeof(struct s) + sizeof(double [m]));
        and assuming that the call to malloc succeeds, the object pointed to by p behaves, for most purposes, as if p had been declared as:
struct { int n; double d[m]; } *p;
(there are circumstances in which this equivalence is broken; in particular, the offsets of member d
might not be the same).
//  Following the above declaration:
Theinitializationoft2isinvalid(andviolatesaconstraint)becausestruct sistreatedasifitdid not contain member d. The assignment to t1.d[0] is probably undefined behavior, but it is possible that
sizeof(struct s) >= offsetof(struct s, d) + sizeof(ouble)
in which case the assignment would be legitimate. Nevertheless, it cannot appear in strictly conforming code.
//  After the further declaration:
struct ss { int n; };
the expressions:
are always equal to 1.
//  If sizeof(double) is 8, then after the following code is executed:
and assuming that the calls to malloc succeed, the objects pointed to by s1 and s2 behave, for most purposes, as if the identifiers had been declared as:
//  Following the further successful assignments:
they then behave as if the declarations were:
struct { int n; double d[1]; } *s1, *s2;
                      struct s t1 = { 0 }; // valid structst2={1,{4.2}}; //invalid
t1.n = 4; // valid
t1.d[0] = 4.2; // might be undefined behavior
                                                   sizeof(struct s) >= sizeof(struct ss) sizeof(struct s) >= offsetof(struct s, d)
                 struct s *s1;
struct s *s2;
s1 = malloc(sizeof(struct s) + 64); s2 = malloc(sizeof(struct s) + 46);
                         struct { int n; double d[8]; } *s1; struct { int n; double d[5]; } *s2;
                 s1 = malloc(sizeof(struct s) + 10); s2 = malloc(sizeof(struct s) + 6);
 and:
//  The assignment:
*s1 = *s2;
onlycopiesthemembern;ifanyofthearrayelementsarewithinthefirstsizeof(struct s)bytes of the structure, they are set to an indeterminate representation, that may or may not coincide with a copy of the representation of the elements of the source array.
//  EXAMPLE 4 Because members of anonymous structures and unions are considered to be members ofthecontainingstructureorunion,struct sinthefollowingexamplehasmorethanonenamed member and thus the use of a flexible array member is valid:
// Forward references: declarators (6.7.6), tags (6.7.2.3).
// 6.7.2.2 Enumeration specifiers
        double *dp;
dp = &(s1->d[0]); // valid
*dp = 42; // valid
dp = &(s2->d[0]); // valid
*dp = 42; // undefined behavior
                                    struct s {
struct { int i; };
int a[]; };
//              Syntax
//  enum-specifier:
enumerator-list:
enum attribute-specifier-sequenceopt identifieropt enum-type-specifieropt { enumerator-list }
enum attribute-specifier-sequenceopt identifieropt enum-type-specifieropt { enumerator-list, }
enum identifier enum-type-specifieropt enumerator
enumerator-list , enumerator
enumerator: enum-type-specifier:
: specifier-qualifier-list
//  All enumerations have an underlying type. The underlying type can be explicitly specified using an enum type specifier and is its fixed underlying type. If it is not explicitly specified, the underlying type is the enumeration’s compatible type, which is either char or a standard or extended signed or unsigned integer type.
Constraints
// For an enumeration with a fixed underlying type, the integer constant expression defining the value of the enumeration constant shall be representable in that fixed underlying type. The definition of an enumeration constant without a defining constant expression shall neither overflow nor wraparound the fixed underlying type by adding 1 to the previous enumeration constant.
// For an enumeration without a fixed underlying type, the expression that defines the value of an enumeration constant shall be an integer constant expression. For all the integer constant expressions which make up the values of the enumeration constants, there shall be a type capable of representing
enumeration-constant attribute-specifier-sequenceopt
enumeration-constant attribute-specifier-sequenceopt = constant-expression
106 Language § 6.7.2.2

N3054 working draft  September 3, 2022 ISO/IEC 9899:2023 (E) all the values that is a standard or extended signed or unsigned integer type, or char.
// If an enum type specifier is present, then the longest possible sequence of tokens that can be interpreted as a specifier qualifier list is interpreted as part of the enum type specifier. It shall name an integer type that is neither an enumeration nor a bit-precise integer type.
//  An enum specifier of the form
enum identifier enum-type-specifier may not appear except in a declaration of the form
enum identifier enum-type-specifier ;
unless it is immediately followed by an opening brace, an enumerator list (with an optional ending
comma), and a closing brace.
// If two enum specifiers that include an enum type specifier declare the same type, the underlying types shall be compatible.
Semantics
//  The optional attribute specifier sequence in the enum specifier appertains to the enumeration; the attributes in that attribute specifier sequence are thereafter considered attributes of the enumeration whenever it is named. The optional attribute specifier sequence in the enumerator appertains to that enumerator.
//  The identifiers in an enumerator list are declared as constants of the types specified below and may appear wherever such are permitted.149) An enumerator with = defines its enumeration constant as the value of the constant expression. If the first enumerator has no =, the value of its enumeration constant is zero. Each subsequent enumerator with no = defines its enumeration constant as the value of the constant expression obtained by adding 1 to the value of the previous enumeration constant. (The use of enumerators with = may produce enumeration constants with values that duplicate other values in the same enumeration.) The enumerators of an enumeration are also known as its members.
//  The type for the members of an enumeration is called the enumeration member type.
//  During the processing of each enumeration constant in the enumerator list, the type of the enumera-
tion constant shall be:
// — the previously declared type, if it is a redeclaration of the same enumeration constant; or,
// — the enumerated type, for an enumeration with fixed underlying type; or,
// — int, if there are no previous enumeration constants in the enumerator list and no explicit = with a defining integer constant expression; or,
// — int, if given explicitly with = and the value of the integer constant expression is representable by an int; or,
// — the type of the integer constant expression, if given explicitly with = and if the value of the integer constant expression is not representable by int; or,
// — the type of the value from the previous enumeration constant with one added to it. If such an integer constant expression would overflow or wraparound the value of the previous enumeration constant from the addition of one, the type takes on either:
// — a suitably sized signed integer type (excluding the bit-precise signed integer types) capable of representing the value of the previous enumeration constant plus one; or,
149)Thus, the identifiers of enumeration constants declared in the same scope are all required to be distinct from each other and from other identifiers declared in ordinary declarators.
//  — a suitably sized unsigned integer type (excluding the bit-precise unsigned integer types)
capable of representing the value of the previous enumeration constant plus one. A signed integer type is chosen if the previous enumeration constant being added is of signed integer type. An unsigned integer type is chosen if the previous enumeration constant is of unsigned integer type. If there is no suitably sized integer type described previously which can represent the new value, then the enumeration has no type which can represent all its values.150)
//  For all enumerations without a fixed underlying type, each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type (excluding the bit-precise integer types). The choice of type is implementation-defined151), but shall be capable of representing the values of all the members of the enumeration152).
//  Enumeration constants can be redefined in the same scope with the same value as part of a redecla- ration of the same enumerated type.
//  The enumeration member type for an enumerated type without fixed underlying type upon comple- tion is:
 int if all the values of the enumeration are representable as an int; or,  the enumerated type.153)
// The enumeration member type for an enumerated type with fixed underlying type is the enumerated type. The enumerated type is compatible with the underlying type of the enumeration. After possible lvalue conversion a value of the enumerated type behaves the same as the value with the underlying type, in particularly with all aspects of promotion, conversion, and arithmetic154).
//  EXAMPLE The following fragment:
makes hue the tag of an enumeration, and then declares col as an object that has that type and cp as a pointer to an object that has that type. The enumerated values are in the set {0, 1, 20, 21}.
//  EXAMPLE Even if the value of an enumeration constant is generated by the implicit addition of one, an enumeration with a fixed underlying type does not exhibit typical overflow behavior:
// 150)Therefore, a constraint has been violated.
// 151)An implementation can delay the choice of which integer type until all enumeration constants have been seen.
// 152)For further rules affecting compatibility and completeness of enumerated types see 6.2.7 and 6.7.2.3.
// 153)The integer type selected during processing of the enumerator list (before completion) of the enumeration may not be the
same as the compatible implementation-defined integer type selected for the completed enumeration.
// 154)This means in particular that if the compatible type is bool, values of the enumerated type behave in all aspects the same as bool and the members only have values false and true. If it is a signed integer type and the constant expression of an
enumeration constant overflows, a constraint for constant expressions (6.6) is violated.
        enum hue { chartreuse, burgundy, claret=20, winedark }; enum hue col, *cp;
col = claret;
cp = &col;
if (*cp != burgundy) /* ... */
                           #include <limits.h>
enum us : unsigned short { us_max = USHRT_MAX,
      us_violation, /* Constraint violation:
                       USHRT_MAX + 1 would wraparound. */
us_violation_2 = us_max + 1, /* Maybe constraint violation:
USHRT_MAX + 1 may be promoted to "int", and
                                      result is too wide for the
   underlying type. */ us_wraparound_to_zero = (unsigned short)(USHRT_MAX + 1) /* Okay:
};
enum ui : unsigned int { ui_max = UINT_MAX,
conversion done in constant expression
before conversion to underlying type:
unsigned semantics okay. */
ui_violation, /* Constraint violation:
                 UINT_MAX + 1 would wraparound. */
ui_no_violation = ui_max + 1, /* Okay: Arithmetic performed as typical unsigned integer arithmetic: conversion from a value that is already 0 to 0. */ ui_wraparound_to_zero = (unsigned int)(UINT_MAX + 1) /* Okay: conversion
};
int main () {
// Same as return 0;
}
done in constant expression before conversion to
underlying type: unsigned semantics okay. */
return ui_wraparound_to_zero + us_wraparound_to_zero;
  18 EXAMPLE The following fragment: #include <limits.h>
enum E1: short;
enum E2: short;
enum E3; /* Constraint violation: E3 forward declaration. */ enum E4 : unsigned long long;
enum E1 : short { m11, m12 }; enum E1 x = m11;
enum E2 : long { m21, m22 }; /* Constraint violation: different underlying types */
enum E3 { m31, m32,
m33 = sizeof(enum E3) /* Constraint violation: E3 is not complete here. */
};
enum E3 : int; /* Constraint violation: E3 previously had no underlying type */
enum E4 : unsigned long long {
m40 = sizeof(enum E4),
m41 = ULLONG_MAX,
m42 /* Constraint violation: unrepresentable value (wraparound) */
};
enum E5 y; /* Constraint violation: incomplete type */
enum E6 : long int z; /* Constraint violation: enum-type-specifier
with identifier in declarator */ enum E7 : long int = 0; /* Syntax violation:
                                       enum-type-specifier with initializer */
demonstrates many of the properties of multiple declarations of enumerations with underlying types.Particularly,enum E3isdeclaredanddefinedwithoutanunderlyingtypefirst,thereforea redeclaration with an underlying type second is a violation. Because it not complete at that time
         § 6.7.2.2 Language 109

ISO/IEC 9899:2023 (E) working draft  September 3, 2022 N3054 withinitsenumeratorlist,sizeof(enum E3)isaconstraintviolationwithintheenum E3definition.
enum E4iscompleteasitisbeingdefined,thereforesizeof(enum E4)isnotaconstraintviolation. 19 EXAMPLE The following fragment:
enum no_underlying { a0
};
int main (void) {
int a = _Generic(a0,
       }
int: 2,
unsigned char: 1, default: 0
);
int b = _Generic((enum no_underlying)a0,
int: 2,
unsigned char: 1, default: 0
);
return a + b;
  demonstrates the implementation-defined nature of the underlying type of enumerations using generic selection (6.5.1.1). The value of a after its initialization is 2. The value of b after its initializa- tion is implementation-defined: the enumeration must be compatible with a type large enough to fit the values of its enumeration constants. Because the only value is 0 for a0, b may hold any of 2, 1, or 0.
Now, consider a similar fragment, but using a fixed underlying type:
enum underlying : unsigned char { b0
};
int main (void) {
int a = _Generic(b0,
       }
int: 2,
unsigned char: 1, default: 0
);
int b = _Generic((enum underlying)b0,
int: 2,
unsigned char: 1, default: 0
);
return 0;
  Here, we are guaranteed that a and b are both initialized to one. This makes enumerations with a fixed underlying type more portable.
20 EXAMPLE Enumerations with a fixed underlying type must have their braces and the enumerator list specified as part of their declaration if they are not a standalone declaration:
        void f1 (enum a : long b); /* Constraint violation */ void f2 (enum c : long { x } d);
enum e : int f3(); /* Constraint violation */
typedef enum t u; /* Constraint violation: forward declaration of t. */ typedef enum v : short W; /* Constraint violation */
typedef enum q : short { s } R;
                  110 Language § 6.7.2.2

N3054
working draft  September 3, 2022
ISO/IEC 9899:2023 (E)
   struct s1 { int x;
enum e : int : 1; /* Constraint violation */
int y; };
enum forward; /* Constraint violation */
extern enum forward fwd_val0; /* Constraint violation: incomplete type */ extern enum forward* fwd_ptr0; /* Constraint violation: enums cannot be
used like other incomplete types */ extern int* fwd_ptr0; /* Constraint violation: incompatible
                         with incomplete type. */
enum forward1 : int;
extern enum forward1 fwd_val1; extern int fwd_val1;
extern enum forward1* fwd_ptr1; extern int* fwd_ptr1;
int main () {
enum e : short;
}
enum e : short f = 0; /* Constraint violation */ enum g : short { y } h = y;
return 0;
Enumerations with a fixed underlying type are complete when the enum type specifier
  21 EXAMPLE
for that specific enumeration is complete. The enumeration e in this snippet:
         enum e : typeof ((enum e : short { A })0, (short)0);
enum eisconsideredcompletebythefirstopeningbracewithinthetypeofinthissnippet. Forward references: generic selection (6.5.1.1), tags (6.7.2.3), declarations (6.7), declarators (6.7.6),
function declarators (6.7.6.3), type names (6.7.7).
6.7.2.3 Tags
Constraints
1 Where two declarations that use the same tag declare the same type, they shall both use the same choice of struct, union, or enum. If two declarations of the same type have a member-declaration or enumerator-list, one shall not be nested within the other and both declarations shall fulfill all requirements of compatible types (6.2.7) with the additional requirement that corresponding members of structure or union types shall have the same (and not merely compatible) types.
2 A type specifier of the form
enum identifier
without an enumerator list shall only appear after the type it specifies is complete.
3 A type specifier of the form
struct-or-union attribute-specifier-sequenceopt identifier
shall not contain an attribute specifier sequence155).
Semantics
4 All declarations of structure, union, or enumerated types that have the same scope and use the same tag declare the same type.
155)As specified in 6.7.2.1 above, the type specifier may be followed by a ; or a member declaration list.
§ 6.7.2.3 Language 111
     
ISO/IEC 9899:2023 (E) working draft  September 3, 2022 N3054
5 Irrespective of whether there is a tag or what other declarations of the type are in the same trans- lation unit, the type (except enumerated types with a fixed underlying type) is incomplete until immediately after the closing brace of the list defining the content for the first time and complete thereafter.
6 Enumerated types with fixed underlying type (6.7.2.2) are complete immediately after their first associated enum type specifier ends.
7 EXAMPLE 1 The following example shows allowed redeclarations of the same structure, union, or enumerated type in the same scope:
        struct foo { struct { int x; }; }; struct foo { struct { int x; }; }; union bar { int x; float y; }; union bar { float y; int x; }; typedef struct q { int x; } q_t; typedef struct q { int x; } q_t; void foo(void)
{
struct S { int x; }; struct T { struct S s; }; struct S { int x; }; struct T { struct S s; };
}
enum X { A = 1, B = 1 + 1 }; enum X { B = 2, A = 1 };
                                              8 EXAMPLE 2 The following example shows invalid redeclarations of the same structure, union, or enumerated type in the same scope:
       struct foo { int (*p)[3]; }; struct foo { int (*p)[]; };
union bar { int x; float y; }; union bar { int z; float y; };
typedef struct { int x; } q_t; typedef struct { int x; } q_t;
struct S { int x; }; void foo(void)
// member has different type
// member has different name
// not the same type
{
struct T { struct S s; };
struct S { int x; };
struct T { struct S s; }; // struct S not the same type
}
enum X { A = 1, B = 2 };
enum X { A = 1, B = 3 };
enum R { C = 1 }; enum Q { C = 1 }; enum Q { C = C };
// different enumeration constant
// conflicting enumeration constant
// ok!
  9 Two declarations of structure, union, or enumerated types which are in different scopes or use different tags declare distinct types. Each declaration of a structure, union, or enumerated type which does not include a tag declares a distinct type.
10 A type specifier of the form
struct-or-union attribute-specifier-sequenceopt identifieropt { member-declaration-list }
112 Language § 6.7.2.3

N3054 working draft  September 3, 2022 ISO/IEC 9899:2023 (E) or
or
enum attribute-specifier-sequenceopt identifieropt { enumerator-list } enum attribute-specifier-sequenceopt identifieropt { enumerator-list , }
declares a structure, union, or enumerated type. The list defines the structure content, union content, or enumeration content. If an identifier is provided156), the type specifier also declares the identifier to be the tag of that type. The optional attribute specifier sequence appertains to the structure, union, or enumeration type being declared; the attributes in that attribute specifier sequence are thereafter considered attributes of the structure, union, or enumeration type whenever it is named.
11 A declaration of the form
struct-or-union attribute-specifier-sequenceopt identifier ;
specifies a structure or union type and declares the identifier as a tag of that type157). The optional attribute specifier sequence appertains to the structure or union type being declared; the attributes in that attribute specifier sequence are thereafter considered attributes of the structure or union type whenever it is named.
12 If a type specifier of the form
struct-or-union attribute-specifier-sequenceopt identifier
occurs other than as part of one of the above forms, and no other declaration of the identifier as a tag is visible, then it declares an incomplete structure or union type, and declares the identifier as the tag of that type.157)
13 If a type specifier of the form
struct-or-union attribute-specifier-sequenceopt identifier
or
enum identifier
occurs other than as part of one of the above forms, and a declaration of the identifier as a tag is
visible, then it specifies the same type as that other declaration, and does not redeclare the tag.
14 EXAMPLE 3 This mechanism allows declaration of a self-referential structure.
specifies a structure that contains an integer and two pointers to objects of the same type. Once this declaration has been given, the declaration
struct tnode s, *sp;
declares s to be an object of the given type and sp to be a pointer to an object of the given type. With these declarations, the expression sp->left refers to the left struct tnode pointer of the object to which sp points; the expression s.right->count designates the count member of the right struct tnodepointedtofroms.
15 The following alternative formulation uses the typedef mechanism:
156)If there is no identifier, the type can, within the translation unit, only be referred to by the declaration of which it is a part. Of course, when the declaration is of a typedef name, subsequent declarations can make use of that typedef name to declare objects having the specified structure, union, or enumerated type.
157)A similar construction with enum does not exist.
§ 6.7.2.3 Language 113
         struct tnode { int count;
        struct tnode *left, *right;
    };
                          typedef struct tnode TNODE; struct tnode {
     
ISO/IEC 9899:2023 (E) working draft  September 3, 2022 N3054
    int count;
TNODE *left, *right;
};
TNODE s, *sp;
             16 EXAMPLE 4 To illustrate the use of prior declaration of a tag to specify a pair of mutually referential structures, the declarations
specify a pair of structures that contain pointers to each other. Note, however, that if s2 were already declared as a tag in an enclosing scope, the declaration D1 would refer to it, not to the tag s2 declared in D2. To eliminate this context sensitivity, the declaration
struct s2;
can be inserted ahead of D1. This declares a new tag s2 in the inner scope; the declaration D2 then completes the specification of the new type.
Forward references: declarators (6.7.6), type definitions (6.7.8).
6.7.2.4 Atomic type specifiers
Syntax
1 atomic-type-specifier:
_Atomic ( type-name )
Constraints
2 Atomic type specifiers shall not be used if the implementation does not support atomic types (see 6.10.9.3).
3 The type name in an atomic type specifier shall not refer to an array type, a function type, an atomic type, or a qualified type.
Semantics
4 The properties associated with atomic types are meaningful only for expressions that are lvalues. If the _Atomic keyword is immediately followed by a left parenthesis, it is interpreted as a type specifier (with a type name), not as a type qualifier.
6.7.2.5 Typeof specifiers
        struct s1 { struct s2 *s2p; /* ... */ }; // D1 struct s2 { struct s1 *s1p; /* ... */ }; // D2
                   Syntax
1 typeof-specifier:
typeof ( typeof-specifier-argument )
typeof_unqual ( typeof-specifier-argument ) typeof-specifier-argument:
expression type-name
2 The typeof and typeof_unqual tokens are collectively called the typeof operators. Constraints
3 The typeof operators shall not be applied to an expression that designates a bit-field member.
Semantics
4 The typeof specifier applies the typeof operators to an expression (6.5) or a type name. If the typeof operators are applied to an expression, they yield the type name representing the type of their
114 Language § 6.7.2.5

N3054 working draft  September 3, 2022 ISO/IEC 9899:2023 (E)
operand158). Otherwise, they produce the type name with any nested typeof specifier evaluated.159) If the type of the operand is a variably modified type, the operand is evaluated; otherwise, the operand is not evaluated.
5 The result of the typeof_unqual operation is the non-atomic unqualified version of the type name that would result from the typeof operation160). The typeof operator preserves all qualifiers.
6 EXAMPLE 1 Type of an expression.
is equivalent to this program:
7 EXAMPLE 2 The following program:
         typeof(1+1) main () { return 0;
}
                     int main () { return 0;
}
                const _Atomic int purr = 0; const int meow = 1;
const char* const animals[] = {
      "aardvark",
      "bluejay",
      "catte",
};
typeof_unqual(meow) main (int argc, char* argv[]) { typeof_unqual(purr) plain_purr; typeof(_Atomic typeof(meow)) atomic_meow; typeof(animals) animals_array; typeof_unqual(animals) animals2_array; return 0;
}
                                                                 is equivalent to this program:
    const _Atomic int purr = 0; const int meow = 1;
const char* const animals[] = {
      "aardvark",
      "bluejay",
      "catte",
};
int main (int argc, char* argv[]) {
int plain_purr;
const _Atomic int atomic_meow;
const char* const animals_array[3]; const char* animals2_array[3]; return 0;
}
                                                                  158)When applied to a parameter declared to have array or function type, the typeof operators yield the adjusted (pointer) type (see 6.9.1).
159)If the typeof specifier argument is itself a typeof specifier, the operand will be evaluated before evaluating the current typeof operator. This happens recursively until a typeof specifier is no longer the operand.
160)_Atomic ( type-name ),withparentheses,isconsideredan_Atomic-qualifiedtype.
§ 6.7.2.5 Language 115

ISO/IEC 9899:2023 (E) working draft  September 3, 2022 N3054
8 EXAMPLE 3 The equivalence between sizeof and typeofs deduction of the type means this
program has no constraint violations:
int main (int argc, char* argv[]) { static_assert(sizeof(typeof(p)) == sizeof(int)); static_assert(sizeof(typeof(p)) == sizeof(p)); static_assert(sizeof(typeof((char)p)) == sizeof(char)); static_assert(sizeof(typeof((char)p)) == sizeof((char)p)); static_assert(sizeof(typeof("meow")) == sizeof(char[5])); static_assert(sizeof(typeof("meow")) == sizeof("meow")); static_assert(sizeof(typeof(argc)) == sizeof(int)); static_assert(sizeof(typeof(argc)) == sizeof(argc)); static_assert(sizeof(typeof(argv)) == sizeof(char**)); static_assert(sizeof(typeof(argv)) == sizeof(argv));
static_assert(sizeof(typeof_unqual(p)) == sizeof(int)); static_assert(sizeof(typeof_unqual(p)) == sizeof(p)); static_assert(sizeof(typeof_unqual((char)p)) == sizeof(char)); static_assert(sizeof(typeof_unqual((char)p)) == sizeof((char)p)); static_assert(sizeof(typeof_unqual("meow")) == sizeof(char[5])); static_assert(sizeof(typeof_unqual("meow")) == sizeof("meow")); static_assert(sizeof(typeof_unqual(argc)) == sizeof(int)); static_assert(sizeof(typeof_unqual(argc)) == sizeof(argc)); static_assert(sizeof(typeof_unqual(argv)) == sizeof(char**)); static_assert(sizeof(typeof_unqual(argv)) == sizeof(argv));
return 0;
}
9 EXAMPLE 4 The following program with nested typeof(...):
is equivalent to this program:
10 EXAMPLE 5 Variable length arrays with typeof operators performs the operation at execution time rather than translation time.
                 int main (int argc, char*[]) { float val = 6.0f;
   return (typeof(typeof_unqual(typeof(argc))))val;
      }
            int main (int argc, char*[]) { float val = 6.0f;
      return (int)val;
   }
            #include <stddef.h>
size_t vla_size (int n) {
typedef char vla_type[n + 3]; vla_type b; // variable length array return sizeof(
typeof_unqual(b)
); // execution-time sizeof, translation-time typeof operation
}
int main () {
return (int)vla_size(10); // vla_size returns 13
}
                                        11 EXAMPLE 6 Nested typeof operators, arrays, and pointers do not perform array to pointer decay. 116 Language § 6.7.2.5

N3054 working draft  September 3, 2022 ISO/IEC 9899:2023 (E)
         int main () {
typeof(typeof(const char*)[4]) y = {
              "a",
      "b",
      "c",
      "d"
}; // 4-element array of "pointer to const char" return 0;
                        }
    12 EXAMPLE 7 Function, pointer, and array types may be substituted with typeof operations. void f(int);
       typeof(f(5)) g(double x) { printf("value %g\n", x);
}
typeof(g)* h;
typeof(true ? g : NULL) k;
void j(double A[5], typeof(A)* B);
extern typeof(double[]) D; typeof(D) C = { 0.7, 99 };
typeof(D) D = { 5, 8.9, 0.1, 99 }; typeof(D) E;
6.7.3 Type qualifiers
// g has type "void(double)"
// h has type "void(*)(double)"
// k has type "void(*)(double)"
// j has type "void(double*, double**)"
// D has an incomplete type
// C has type "double[2]"
// D is now completed to "double[4]"
// E has type "double[4]" from D’s completed type
  Syntax
1 type-qualifier:
Constraints
const
restrict
volatile
_Atomic
2 Types other than pointer types whose referenced type is an object type and (possibly multi- dimensional) array types with such pointer types as element type shall not be restrict-qualified.
3 The _Atomic qualifier shall not be used if the implementation does not support atomic types (see 6.10.9.3).
4 The type modified by the _Atomic qualifier shall not be an array type or a function type. Semantics
5 The properties associated with qualified types are meaningful only for expressions that are lval- ues.161)
6 If the same qualifier appears more than once in the same specifier-qualifier list or as declaration specifiers, either directly, via one or more typeof specifiers, or via one or more typedefs, the behavior is the same as if it appeared only once. If other qualifiers appear along with the _Atomic qualifier the resulting type is the so-qualified atomic type.
7 If an attempt is made to modify an object defined with a const-qualified type through use of an
161)The implementation can place a const object that is not volatile in a read-only region of storage. Moreover, the implementation need not allocate storage for such an object if its address is never used.
 § 6.7.3 Language 117

ISO/IEC 9899:2023 (E) working draft  September 3, 2022 N3054
lvalue with non-const-qualified type, the behavior is undefined. If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.162)
8 An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore, any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously.163) What constitutes an access to an object that has volatile-qualified type is implementation-defined.
9 An object that is accessed through a restrict-qualified pointer has a special association with that pointer. This association, defined in 6.7.3.1 below, requires that all accesses to that object use, directly or indirectly, the value of that pointer.164) The intended use of the restrict qualifier (like the register storage class) is to promote optimization, and deleting all instances of the qualifier from all preprocessing translation units composing a conforming program does not change its meaning (i.e., observable behavior).
10 If the specification of an array type includes any type qualifiers, both the array and the element type are so-qualified. If the specification of a function type includes any type qualifiers, the behavior is undefined.165)
11 For two qualified types to be compatible, both shall have the identically qualified version of a compatible type; the order of type qualifiers within a list of specifiers or qualifiers does not affect the specified type.
12 EXAMPLE 1 An object declared
extern const volatile int real_time_clock;
might be modifiable by hardware, but cannot be assigned to, incremented, or decremented.
13 EXAMPLE 2 The following declarations and expressions illustrate the behavior when type qualifiers modify an aggregate type:
                    const struct s { int mem; } cs = { 1 };
struct s ncs; // the object ncs is modifiable
typedef int A[2][3];
const A a = {{4, 5, 6}, {7, 8, 9}}; // array of array of const int int *pi;
const int *pci;
ncs = cs; // valid
cs = ncs; // violates modifiable lvalue constraint for = pi = &ncs.mem; // valid
pi = &cs.mem; // violates type constraints for =
pci = &cs.mem; // valid
pi = a[0]; // invalid: a[0] has type "const int *"
                                        14 EXAMPLE 3 The declaration _Atomic volatile int *p;
162)This applies to those objects that behave as if they were defined with qualified types, even if they are never actually defined as objects in the program (such as an object at a memory-mapped input/output address).
163)A volatile declaration can be used to describe an object corresponding to a memory-mapped input/output port or an object accessed by an asynchronously interrupting function. Actions on objects so declared are not allowed to be "optimized out" by an implementation or reordered except as permitted by the rules for evaluating expressions.
164)For example, a statement that assigns a value returned by malloc to a single pointer establishes this association between the allocated object and the pointer.
165)This can occur with typedef s. Note that this rule does not apply to the _Atomic qualifier, and that qualifiers do not have any direct effect on the array type itself, but affect conversion rules for pointer types that reference an array type.
             118 Language § 6.7.3

N3054 working draft  September 3, 2022 ISO/IEC 9899:2023 (E) specifies that p has the type "pointer to volatile atomic int", a pointer to a volatile-qualified atomic
type.
§ 6.7.3 Language 119

ISO/IEC 9899:2023 (E) working draft  September 3, 2022 N3054 6.7.3.1 Formal definition of restrict
1 Let D be a declaration of an ordinary identifier that provides a means of designating an object P as a restrict-qualified pointer to type T.
2 If D appears inside a block and does not have storage class extern, let B denote the block. If D appears in the list of parameter declarations of a function definition, let B denote the associated block. Otherwise, let B denote the block of main (or the block of whatever function is called at program startup in a freestanding environment).
3 In what follows, a pointer expression E is said to be based on object P if (at some sequence point in the execution of B prior to the evaluation of E) modifying P to point to a copy of the array object into which it formerly pointed would change the value of E.166) Note that "based" is defined only for expressions with pointer types.
4 During each execution of B, let L be any lvalue that has &L based on P. If L is used to access the value of the object X that it designates, and X is also modified (by any means), then the following requirements apply: T shall not be const-qualified. Every other lvalue used to access the value of X shall also have its address based on P. Every access that modifies X shall be considered also to modify P, for the purposes of this subclause. If P is assigned the value of a pointer expression E that is based on another restricted pointer object P2, associated with block B2, then either the execution of B2 shall begin before the execution of B, or the execution of B2 shall end prior to the assignment. If these requirements are not met, then the behavior is undefined.
5 Here an execution of B means that portion of the execution of the program that would correspond to the lifetime of an object with scalar type and automatic storage duration associated with B.
6 A translator is free to ignore any or all aliasing implications of uses of restrict.
7 EXAMPLE 1 The file scope declarations
assert that if an object is accessed using one of a, b, or c, and that object is modified anywhere in the program, then it is never accessed using either of the other two.
8 EXAMPLE 2 The function parameter declarations in the following example
assert that, during each execution of the function, if an object is accessed through one of the pointer parameters, then it is not also accessed through the other. The translator can make this no-aliasing inference based on the parameter declarations alone, without analyzing the function body.
9 The benefit of the restrict qualifiers is that they enable a translator to make an effective dependence analysis of function f without examining any of the calls of f in the program. The cost is that the programmer has to examine all those calls to ensure that none give undefined behavior. For example, the second call of f in g has undefined behavior because each of d[1] through d[49] is accessed through both p and q.
166)In other words, E depends on the value of P itself rather than on the value of an object referenced indirectly through P. Forexample,ifidentifierphastype(int **restrict),thenthepointerexpressionspandp+1arebasedontherestricted pointer object designated by p, but the pointer expressions *p and p[1] are not.
        int * restrict a; int * restrict b; extern int c[];
                  void f(int n, int * restrict p, int * restrict q) {
      while (n-- > 0) *p++ = *q++;
      }
            void g(void) {
extern int d[100];
f(50, d + 50, d); // valid
          120 Language § 6.7.3.1

N3054 working draft  September 3, 2022 ISO/IEC 9899:2023 (E)
     f(50, d + 1, d); // undefined behavior
    }
EXAMPLE 3 The function parameter declarations
illustrate how an unmodified object can be aliased through two restricted pointers. If a and b are disjoint arrays, a call of the form h(100, a, b, b) has defined behavior, because array b is not modified within function h.
11 EXAMPLE 4 The rule limiting assignments between restricted pointers does not distinguish be- tween a function call and an equivalent nested block. With one exception, only "outer-to-inner" assignments between restricted pointers declared in nested blocks have defined behavior.
void h(int n, int * restrict p, int * restrict q, int * restrict r) {
int i;
for(i=0;i < n;i++)
      p[i] = q[i] + r[i];
}
{
int * restrict p1;
int * restrict q1;
p1 = q1; // undefined behavior {
int * restrict p2 = p1; // valid
int * restrict q2 = q1; // valid
p1 = q2; // undefined behavior p2 = q2; // undefined behavior
} }
12 The one exception allows the value of a restricted pointer to be carried out of the block in which it (or, more precisely, the ordinary identifier used to designate it) is declared when that block finishes execution. For example, this permits new_vector to return a vector.
13 EXAMPLE 5 Suppose that a programmer knows that references of the form p[i] and q[j] are never aliases in the body of a function:
void f(int n, int *p, int *q) { /* ... */ }
There are several ways that this information could be conveyed to a translator using the restrict qualifier. Example 2 shows the most effective way, qualifying all pointer parameters, and can be used provided that neither p nor q becomes based on the other in the function body. A potentially effective alternative is:
void f(int n, int * restrict p, int * const q) { /* ... */ }
Again, it is possible for a translator to make the no-aliasing inference based on the parameter declarations alone, though now it must use subtler reasoning: that the const-qualification of q precludes it becoming based on p. There is also a requirement that q is not modified, so this alternative cannot be used for the function in Example 2, as written.
14 EXAMPLE 6 Another potentially effective alternative is:
122 Language § 6.7.3.1
typedef struct { int n; float * restrict v; } vector; vector new_vector(int n)
{
vector t;
t.n = n;
t.v = malloc(n * sizeof (float)); return t;
}
N3054 working draft  September 3, 2022 ISO/IEC 9899:2023 (E)
         void f(int n, int *p, int const * restrict q) { /* ... */ }
Again, it is possible for a translator to make the no-aliasing inference based on the parameter declarations alone, though now it must use even subtler reasoning: that this combination of restrict and const means that objects referenced using q cannot be modified, and so no modified object can be referenced using both p and q.
    § 6.7.3.1 Language 123

ISO/IEC 9899:2023 (E) working draft  September 3, 2022 N3054 15 EXAMPLE 7 The least effective alternative is:
void f(int n, int * restrict p, int *q) { /* ... */ }
Here the translator can make the no-aliasing inference only by analyzing the body of the function and proving that q cannot become based on p. Some translator designs may choose to exclude this analysis, given availability of the more effective alternatives above. Such a translator is required to assume that aliases are present because assuming that aliases are not present may result in an incorrect translation. Also, a translator that attempts the analysis may not succeed in all cases and consequently need to conservatively assume that aliases are present.
6.7.4 Function specifiers
Syntax
1 function-specifier:
inline
_Noreturn
Constraints
2 Function specifiers shall be used only in the declaration of an identifier for a function.
3 An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static or thread storage duration, and shall not contain a reference to an identifier with internal linkage.
4 In a hosted environment, no function specifier(s) shall appear in a declaration of main. Semantics
5 A function specifier may appear more than once; the behavior is the same as if it appeared only once.
6 A function declared with an inline function specifier is an inline function. Making a function an inline function suggests that calls to the function be as fast as possible.167) The extent to which such suggestions are effective is implementation-defined.168)
7 Any function with internal linkage can be an inline function. For a function with external linkage, the following restrictions apply: If a function is declared with an inline function specifier, then it shall also be defined in the same translation unit. If all the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function and does not forbid an external definition in another translation unit. Inline definitions provide an alternative to external definitions, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.169)
8 A function declared with a _Noreturn function specifier shall not return to its caller. The attribute [[noreturn]] provides similar semantics. The _Noreturn function specifier is an obsolescent feature (6.7.12.6).
Recommended practice
9 The implementation should produce a diagnostic message for a function declared with a _Noreturn function specifier that appears to be capable of returning to its caller.
167)By using, for example, an alternative to the usual function call mechanism, such as "inline substitution". Inline substitution is not textual substitution, nor does it create a new function. Therefore, for example, the expansion of a macro used within the body of the function uses the definition it had at the point the function body appears, and not where the function is called; and identifiers refer to the declarations in scope where the body occurs. Likewise, the function has a single address, regardless of the number of inline definitions that occur in addition to the external definition.
168)For example, an implementation might never perform inline substitution, or might only perform inline substitutions to calls in the scope of an inline declaration.
169)Since an inline definition is distinct from the corresponding external definition and from any other corresponding inline definitions in other translation units, all corresponding objects with static storage duration are also distinct in each of the definitions.
             124 Language § 6.7.4

N3054 working draft  September 3, 2022 ISO/IEC 9899:2023 (E)
10 EXAMPLE 1 The declaration of an inline function with external linkage can result in either an external definition, or a definition available for use only within the translation unit. A file scope declaration with extern creates an external definition. The following example shows an entire translation unit.
inline double fahr(double t) {
return (9.0 * t) / 5.0 + 32.0; inline double cels(double t)
       }
{
}
return (5.0 * (t - 32.0)) / 9.0;
extern double fahr(double); // creates an external definition
double convert(int is_fahr, double temp)
{
}
/* A translator may perform inline substitutions */ return is_fahr ? cels(temp): fahr(temp);
  11 Note that the definition of fahr is an external definition because fahr is also declared with extern, but the definition of cels is an inline definition. Because cels has external linkage and is referenced, an external definition has to appear in another translation unit (see 6.9); the inline definition and the external definition are distinct and either can be used for the call.
Forward references: function definitions (6.9.1).
6.7.5 Alignment specifier
Syntax
1 alignment-specifier:
alignas ( type-name )
alignas ( constant-expression )
Constraints
2 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.
3 The constant expression shall be an integer constant expression. It shall evaluate to a valid funda- mental alignment, or to a valid extended alignment supported by the implementation for an object of the storage duration (if any) being declared, or to zero.
4 An object shall not be declared with an over-aligned type with an extended alignment requirement not supported by the implementation for an object of that storage duration.
5 The combined effect of all alignment specifiers in a declaration shall not specify an alignment that is less strict than the alignment that would otherwise be required for the type of the object or member being declared.
Semantics
6 The first form is equivalent to alignas(alignof( type-name)).
7 The alignment requirement of the declared object or member is taken to be the specified alignment.
§ 6.7.5 Language 125

ISO/IEC 9899:2023 (E) working draft  September 3, 2022 N3054 An alignment specification of zero has no effect.170) When multiple alignment specifiers occur in a
declaration, the effective alignment requirement is the strictest specified alignment.
8 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.
6.7.6 Declarators
Syntax
1 declarator: direct-declarator:
array-declarator:
pointeropt direct-declarator
identifier attribute-specifier-sequenceopt
( declarator )
array-declarator attribute-specifier-sequenceopt function-declarator attribute-specifier-sequenceopt
direct-declarator [ type-qualifier-listopt assignment-expressionopt ] direct-declarator [ static type-qualifier-listopt assignment-expression ] direct-declarator [ type-qualifier-list static assignment-expression ] direct-declarator [ type-qualifier-listopt * ]
function-declarator:
direct-declarator ( parameter-type-listopt )
pointer: type-qualifier-list: parameter-type-list:
parameter-list:
* attribute-specifier-sequenceopt type-qualifier-listopt
* attribute-specifier-sequenceopt type-qualifier-listopt pointer
type-qualifier
type-qualifier-list type-qualifier
parameter-list parameter-list , ... ...
parameter-declaration
parameter-list , parameter-declaration parameter-declaration:
attribute-specifier-sequenceopt declaration-specifiers declarator attribute-specifier-sequenceopt declaration-specifiers abstract-declaratoropt
Semantics
2 Each declarator declares one identifier, and asserts that when an operand of the same form as the declarator appears in an expression, it designates a function or object with the scope, storage duration, and type indicated by the declaration specifiers.
3 A full declarator is a declarator that is not part of another declarator. If, in the nested sequence of declarators in a full declarator, there is a declarator specifying a variable length array type, the type specified by the full declarator is said to be variably modified. Furthermore, any type derived by declarator type derivation from a variably modified type is itself variably modified.
170)An alignment specification of zero also does not affect other alignment specifications in the same declaration.
126 Language § 6.7.6
 
N3054 working draft  September 3, 2022 ISO/IEC 9899:2023 (E)
4 In the following subclauses, consider a declaration
T D1
where T contains the declaration specifiers that specify a type T (such as int) and D1 is a declarator that contains an identifier ident. The type specified for the identifier ident in the various forms of declarator is described inductively using this notation.
5 If, in the declaration "T D1", D1 has the form identifier attribute-specifier-sequenceopt
then the type specified for ident is T and the optional attribute specifier sequence appertains to the entity that is declared.
6 If, in the declaration "T D1", D1 has the form (D)
then ident has the type specified by the declaration "T D". Thus, a declarator in parentheses is identical to the unparenthesized declarator, but the binding of complicated declarators may be altered by parentheses.
Implementation limits
7 As discussed in 5.2.4.1, an implementation may limit the number of pointer, array, and function declarators that modify an arithmetic, structure, union, or void type, either directly or via one or more typedef s.
Forward references: array declarators (6.7.6.2), type definitions (6.7.8).
6.7.6.1 Pointer declarators
Semantics
1 If, in the declaration "T D1", D1 has the form
* attribute-specifier-sequenceopt type-qualifier-listopt D
andthetypespecifiedforidentinthedeclaration"T D"is"derived-declarator-type-listT",thenthe type specified for ident is "derived-declarator-type-list type-qualifier-list pointer to T". For each type qualifier in the list, ident is a so-qualified pointer. The optional attribute specifier sequence appertains to the pointer and not the object pointed to.
2 For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
3 EXAMPLE The following pair of declarations demonstrates the difference between a "variable pointer to a constant value" and a "constant pointer to a variable value".
The contents of any object pointed to by ptr_to_constant cannot be modified through that pointer, but ptr_to_constant itself can be changed to point to another object. Similarly, the contents of the int pointed to by constant_ptr can be modified, but constant_ptr itself always points to the same location.
4 The declaration of the constant pointer constant_ptr can be clarified by including a definition for the type "pointer to int".
declares constant_ptr as an object that has type "const-qualified pointer to int".
§ 6.7.6.1 Language 127
    const int *ptr_to_constant; int *const constant_ptr;
                 typedef int *int_ptr;
const int_ptr constant_ptr;
             
ISO/IEC 9899:2023 (E) working draft  September 3, 2022 N3054
6.7.6.2 Array declarators
Constraints
1 In addition to optional type qualifiers and the keyword static, the [ and ] may delimit an expres- sion or *. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero. The element type shall not be an incomplete or function type. The optional type qualifiers and the keyword static shall appear only in a declaration of a function parameter with an array type, and then only in the outermost array type derivation.
2 If an identifier is declared as having a variably modified type, it shall be an ordinary identifier (as defined in 6.2.3), have no linkage, and have either block scope or function prototype scope. If an identifier is declared to be an object with static or thread storage duration, it shall not have a variable length array type.
Semantics
3 If, in the declaration "T D1", D1 has one of the forms:
D [ type-qualifier-listopt assignment-expressionopt ] attribute-specifier-sequenceopt
D [ static type-qualifier-listopt assignment-expression ] attribute-specifier-sequenceopt D [ type-qualifier-list static assignment-expression ] attribute-specifier-sequenceopt D [ type-qualifier-listopt * ] attribute-specifier-sequenceopt
andthetypespecifiedforidentinthedeclaration"T D"is"derived-declarator-type-listT",thenthe type specified for ident is "derived-declarator-type-list array of T".171)172) The optional attribute specifier sequence appertains to the array. (See 6.7.6.3 for the meaning of the optional type qualifiers and the keyword static.)
4 If the size is not present, the array type is an incomplete type. If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations or type names with function prototype scope173); such arrays are nonetheless complete types. If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type. (Variable length arrays with automatic storage duration are a conditional feature that implementations need not support; see 6.10.9.3.)
5 If the size is an expression that is not an integer constant expression: if it occurs in a declaration at function prototype scope, it is treated as if it were replaced by *; otherwise, each time it is evaluated it shall have a value greater than zero. The size of each instance of a variable length array type does not change during its lifetime. Where a size expression is part of the operand of a typeof or sizeof operator and changing the value of the size expression would not affect the result of the operator, it is unspecified whether or not the size expression is evaluated. Where a size expression is part of the operand of an alignof operator, that expression is not evaluated.
6 For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are integer constant expressions, then both size specifiers shall have the same constant value. If the two array types are used in a context which requires them to be compatible, it is undefined behavior if the two size specifiers evaluate to unequal values.
7 EXAMPLE 1
float fa[11], *afp[17];
declares an array of float numbers and an array of pointers to float numbers.
8 EXAMPLE 2 Note the distinction between the declarations
171)When several "array of" specifications are adjacent, a multidimensional array is declared. 172)The array is considered identically qualified to T according to 6.2.5.
173)Thus, * can be used only in function declarations that are not definitions (see 6.7.6.3).
                    extern int *x; extern int y[];
        128 Language
§ 6.7.6.2

N3054 working draft  September 3, 2022 ISO/IEC 9899:2023 (E) The first declares x to be a pointer to int; the second declares y to be an array of int of unspecified
size (an incomplete type), the storage for which is defined elsewhere.
9 EXAMPLE 3 The following declarations demonstrate the compatibility rules for variably modified types.
         extern int n; extern int m;
void fcompat(void) {
                    int a[n][6][m];
int (*p)[4][n+1];
int c[n][n][6][m];
int (*r)[n][n][n+1];
p = a; // invalid: not compatible because 4 != 6 r = c; // compatible, but defined behavior only if
// n == 6 and m == n+1
                            }
    10 EXAMPLE 4 All declarations of variably modified (VM) types have to be at either block scope or function prototype scope. Array objects declared with the thread_local, static, or extern storage-class specifier cannot have a variable length array (VLA) type. However, an object declared with the static storage-class specifier can have a VM type (that is, a pointer to a VLA type). Finally, all identifiers declared with a VM type have to be ordinary identifiers and cannot, therefore, be members of structures or unions.
       extern int n;
int A[n];
extern int (*p2)[n]; int B[100];
void fvla(int m, int C[m][m]); void fvla(int m, int C[m][m])
// invalid:  file scope VLA
// invalid:  file scope VM
// valid:  file scope but not VM
// valid: VLA with prototype scope
// valid: adjusted to auto pointer to VLA // valid: block scope typedef VLA
// invalid: y not ordinary identifier // invalid: z not ordinary identifier
// valid: auto VLA
// invalid: static block scope VLA
// invalid: F has linkage and is VLA
// valid: auto pointer to VLA
// invalid: r has linkage and points to VLA // valid: q is a static block pointer to VLA
{
}
typedef int VLA[m][m];
struct tag {
int (*y)[n];
int z[n];
};
int D[m];
static int E[m];
extern int F[m];
int (*s)[m];
extern int (*r)[m]; static int (*q)[m] = &B;
  Forward references: function declarators (6.7.6.3), function definitions (6.9.1), initialization (6.7.10).
6.7.6.3 Function declarators
Constraints
1 A function declarator shall not specify a return type that is a function type or an array type.
2 The only storage-class specifier that shall occur in a parameter declaration is register.
3 After adjustment, the parameters in a parameter type list in a function declarator that is part of a definition of that function shall not have incomplete type.
§ 6.7.6.3 Language 129

ISO/IEC 9899:2023 (E) working draft  September 3, 2022 N3054 Semantics
4 If, in the declaration "T D1", D1 has the form
D ( parameter-type-listopt ) attribute-specifier-sequenceopt
andthetypespecifiedforidentinthedeclaration"T D"is"derived-declarator-type-listT",thenthe type specified for ident is "derived-declarator-type-list function returning the unqualified version of T". The optional attribute specifier sequence appertains to the function type.
5 A parameter type list specifies the types of, and may declare identifiers for, the parameters of the function.
6 A declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type", where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
7 A declaration of a parameter as "function returning type" shall be adjusted to "pointer to function returning type", as in 6.3.2.1.
8 If the list terminates with an ellipsis (...), no information about the number or types of the parameters after the comma is supplied. 174)
9 The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters.
10 If, in a parameter declaration, an identifier can be treated either as a typedef name or as a parameter name, it shall be taken as a typedef name.
//  If the function declarator is not part of a definition of that function, parameters may have incomplete type and may use the [*] notation in their sequences of declarator specifiers to specify variable length array types.
//  The storage class specifier in the declaration specifiers for a parameter declaration, if present, is ignored unless the declared parameter is one of the members of the parameter type list for a function definition. The optional attribute specifier sequence in a parameter declaration appertains to the parameter.
//  For a function declarator without a parameter type list: the effect is as if it were declared with a parameter type list consisting of the keyword void. A function declarator provides a prototype for the function175).
//  For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists shall agree in the number of parameters and in use of the final ellipsis; corresponding parameters shall have compatible types. In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.
//  EXAMPLE 1 The declaration
int f(void), *fip(), (*pfi)();
// declares a function f with no parameters returning an int, a function fip with no parameters returning a pointer to an int, and a pointer pfi to a function with no parameters returning an int. It is especially useful to compare the last two. The binding of *fip() is *(fip()), so that the declaration suggests, and the same construction in an expression requires, the calling of a function fip, and then using indirection through the pointer result to yield an int. In the declarator (*pfi) (), the extra parentheses are necessary to indicate that indirection through a pointer to a function
// 174)The macros defined in the <stdarg.h> header (7.16) can be used to access arguments that correspond to the ellipsis.
// 175)This implies that a function definition without a parameter list provides a prototype, and that subsequent calls to that function in the same translation unit are constrained not to provide any argument to the function call. Thus a definition of a function without parameter list and one that has such a list consisting of the keyword void are fully equivalent.
// yields a function designator, which is then used to call the function; it returns an int.
//  If the declaration occurs outside of any function, the identifiers have file scope and external linkage. If the declaration occurs inside a function, the identifiers of the functions f and fip have block scope and either internal or external linkage (depending on what file scope declarations for these identifiers are visible), and the identifier of the pointer pfi has block scope and no linkage.
//  EXAMPLE 2 The declaration
int (*apfi[3])(int *x, int *y);
// declares an array apfi of three pointers to functions returning int. Each of these functions has two parameters that are pointers to int. The identifiers x and y are declared for descriptive purposes only and go out of scope at the end of the declaration of apfi.
//  EXAMPLE 3 The declaration
int (*fpfi(int (*)(long), int))(int, ...);
// declares a function fpfi that returns a pointer to a function returning an int. The function fpfi has twoparameters:apointertoafunctionreturninganint(withoneparameteroftypelong int), and an int. The pointer returned by fpfi points to a function that has one int parameter and accepts zero or more additional arguments of any type.
//  EXAMPLE 4 The following prototype has a variably modified parameter. void addscalar(int n, int m,
double a[n][n*m+300], double x); int main(void)
{
double b[4][308]; addscalar(4, 2, b, 2.17); return 0;
}
void addscalar(int n, int m,
                                 {
}
double a[n][n*m+300], double x)
for(inti=0;i < n;i++) for(intj=0,k=n*m+300;j < k;j++)
// a is a pointer to a VLA with n*m+300 elements a[i][j] += x;
//  EXAMPLE 5 The following are all compatible function prototype declarators. as are:
// (Note that the last declaration also specifies that the argument corresponding to a in any call to f can be expected to be a non-null pointer to the first of at least three arrays of 5 doubles, which the
         double maximum(int n, int m, double a[n][m]); double maximum(int n, int m, double a[*][*]); double maximum(int n, int m, double a[ ][*]); double maximum(int n, int m, double a[ ][m]);
                         void f(double (* restrict a)[5]);
void f(double a[restrict][5]);
void f(double a[restrict 3][5]);
void f(double a[restrict static 3][5]);
//  others do not.)
// Forward references: function definitions (6.9.1), type names (6.7.7).
// 6.7.7 Type names
// Syntax
//  type-name: specifier-qualifier-list abstract-declaratoropt abstract-declarator: pointer pointeropt direct-abstract-declarator direct-abstract-declarator:
( abstract-declarator ) array-abstract-declarator attribute-specifier-sequenceopt function-abstract-declarator attribute-specifier-sequenceopt  array-abstract-declarator: direct-abstract-declaratoropt direct-abstract-declaratoropt direct-abstract-declaratoropt direct-abstract-declaratoropt
function-abstract-declarator: direct-abstract-declaratoropt
// Semantics
[ type-qualifier-listopt assignment-expressionopt ]
[ static type-qualifier-listopt assignment-expression ] [ type-qualifier-list static assignment-expression ]
[ * ]
( parameter-type-listopt )
//  In several contexts, it is necessary to specify a type. This is accomplished using a type name, which is syntactically a declaration for a function or an object of that type that omits the identifier.176) The optional attribute specifier sequence in a direct abstract declarator appertains to the preceding array or function type. The attribute specifier sequence affects the type only for the declaration it appears in, not other declarations involving the same type.
//  EXAMPLE The constructions
name respectively the types (a) int, (b) pointer to int, (c) array of three pointers to int, (d) pointer to an array of three int s, (e) pointer to a variable length array of an unspecified number of int s, (f) function with no parameters returning a pointer to int, (g) pointer to function with no parameters returning an int, and (h) array of an unspecified number of constant pointers to functions, each withoneparameterthathastypeunsigned intandanunspecifiednumberofotherparameters, returning an int.
// 6.7.8 Type definitions
// Syntax
/*        (a) int
(b) int *
(c) int *[3]
(d) int (*)[3]
(e) int (*)[*]
(f) int *()
(g) int (*)(void)
(h) int (*const [])(unsigned int, ...)*/
                    //  typedef-name:
// 176)As indicated by the syntax, empty parentheses in a type name are interpreted as "function with no parameter specification", rather than redundant parentheses around the omitted identifier.
// Constraints
//  If a typedef name specifies a variably modified type then it shall have block scope.
// Semantics
//  In a declaration whose storage-class specifier is typedef, each declarator defines an identifier to be a typedef name that denotes the type specified for the identifier in the way described in 6.7.6. Any array size expressions associated with variable length array declarators are evaluated each time the declaration of the typedef name is reached in the order of execution. A typedef declaration does not introduce a new type, only a synonym for the type so specified. That is, in the following declarations: type_ident is defined as a typedef name with the type specified by the declaration specifiers in T (known as T), and the identifier in D has the type "derived-declarator-type-list T" where the derived- declarator-type-list is specified by the declarators of D. A typedef name shares the same name space as other identifiers declared in ordinary declarators. If the identifier is redeclared in an enclosed block, the type of the inner declaration shall not be inferred (6.7.9).
// EXAMPLE 1 After the constructions are all valid declarations. The type of distance is int, that of metricp is "pointer to function with no parameters returning int", and that of x and z is the specified structure; zp is a pointer to such a structure. The object distance has a type compatible with any other int object.
//  EXAMPLE 2 After the declarations
type t1 and the type pointed to by tp1 are compatible. Type t1 is also compatible with type struct s1,butnotcompatiblewiththetypesstruct s2,t2,thetypepointedtobytp2,orint.
//  EXAMPLE 3 The following obscure constructions
declare a typedef name t with type signed int, a typedef name plain with type int, and a structure with three bit-field members, one named t that contains values in the range [0, 15], an unnamed const-qualified bit-field which (if it could be accessed) would contain values in the range
    typedef T type_ident; type_ident D;
                      typedef int MILES, KLICKSP();
typedef struct { double hi, lo; } range;
                 MILES distance;
extern KLICKSP *metricp; range x;
range z, *zp;
                         typedef struct s1 { int x; } t1, *tp1; typedef struct s2 { int x; } t2, *tp2;
                 typedef signed int t; typedef int plain; struct tag {
            unsigned t:4; const t:5; plain r:5;
            };
// [−16, +15], and one named r that contains values in one of the ranges [0, 31] or [−16, +15]. (The choice of range is implementation-defined.) The first two bit-field declarations differ in that unsigned is a type specifier (which forces t to be the name of a structure member), while const is a type qualifier (which modifies t which is still visible as a typedef name). If these declarations are followed in an inner scope by
thenafunctionfisdeclaredwithtype"functionreturningsigned intwithoneunnamedparame- terwithtypepointertofunctionreturningsigned intwithoneunnamedparameterwithtype signed int",andanidentifiertwithtypelong int.
//  EXAMPLE 4 On the other hand, typedef names can be used to improve code readability. All three of the following declarations of the signal function specify exactly the same type, the first without making use of any typedef names.
//  EXAMPLE 5 If a typedef name denotes a variable length array type, the length of the array is fixed at the time the typedef name is defined, not each time it is used:
        t f(t (t)); long t;
               typedef void fv(int), (*pfv)(int);
void (*signal(int, void (*)(int)))(int); fv *signal(int, fv *);
pfv signal(int, pfv);
                        void copyt(int n) {
}
// B is n ints, n evaluated now // a is n ints, n without += 1
      typedef int B[n];
n += 1;
B a;
int b[n];
for(inti=1;i < n;i++)
         // a and b are different sizes a[i-1] = b[i];
//              6.7.9 Type inference
// Constraints
//  A declaration for which the type is inferred shall contain the storage-class specifier auto. Description
//  For such a declaration that is the definition of an object the init-declarator shall have one of the forms
direct-declarator = assignment-expression direct-declarator = { assignment-expression } direct-declarator = { assignment-expression , }
The declared type is the type of the assignment expression after lvalue, array to pointer or function to pointer conversion, additionally qualified by qualifiers and amended by attributes as they appear in the declaration specifiers, if any177). If the direct declarator is not of the form identifier attribute-specifier-sequenceopt
optionally enclosed in balanced pairs of parentheses, the behavior is undefined.
//  NOTE 1 Such a declaration that also defines a structure or union type violates a constraint. Here, the identifier x which is not ordinary but in the name space of the structure type is declared.
// 177)The scope rules as described in 6.2.1 also prohibit the use of the identifier of the declarator within the assignment expression.
         auto p = (struct { int x; } *)0; Even a forward declaration of a structure tag
would not change that situation. A direct use of the structure definition as the type specifier ensures the validity of the declaration.
struct s { int x; } * p = 0;
//  EXAMPLE 1 Consider the following file scope definitions:
They are interpreted as if they had been written as:
So effectively a is a double and p is a double*. Note that the restrictions on the syntax of such declarations does not allow the declarator to be *p, but that the final type here nevertheless is a pointer type.
//  EXAMPLE 2 The scope of the identifier for which the type is inferred only starts after the end of the initializer (6.2.1), so the assignment expression cannot use the identifier to refer to the object or function that is declared, for example to take its address. Any use of the identifier in the initializer is invalid, even if an entity with the same name exists in an outer scope.
             struct s;
auto p = (struct s { int x; } *)0;
                              static auto a = 3.5; auto p = &a;
                 static double a = 3.5; double * p = &a;
               {
}
double a = 7; double b = 9; {
} {
}
= a * a; = b;
// ...
double b = b * b; // undefined, uses uninitialized // variable without address
printf("%g\n", a);
// valid, uses "a" from outer scope, prints 7
// invalid, "a" from outer scope is not
// visible during variable initialization
// valid, uses "a" from outer scope
// valid, "a" from outer scope not visible now
// valid, uses "a" from inner scope, prints 49
auto a
auto b
auto a
// ... printf("%g\n", a);
= a * a;
//  EXAMPLE 3 In the following, declarations of pA and qA are valid. The type of A after array-to- pointer conversion is a pointer type, and qA is a pointer to array.
//  EXAMPLE 4 Type inference can be used to capture the type of a call to a type-generic function. It ensures that the same type as the argument x is used.
         double A[3] = { 0 }; auto pA = A;
auto qA = &A;
        #include <tgmath.h>
 auto y = cos(x);
       If instead the type of y is explicitly specified to a different type than x, a diagnosis of the mismatch is not enforced.
//  EXAMPLE 5 A type-generic macro that generalizes the div functions (7.24.6.2) is defined and used as follows.
// EXAMPLE 6 Definitions of objects with inferred type are valid in all contexts that allow the initial- izer syntax as described. In particular they can be used to ensure type safety of for-loop controlling expressions.
Here, regardless of the integer rank or signedness of the type of j, i will have the non-atomic unqualified type of j. So, after lvalue conversion and possible promotion, the two operands of the < operator in the controlling expression are guaranteed to have the same type, and, in particular, the same signedness.
6.7.10 Initialization
Syntax
//  braced-initializer:
{}
    #define div(X, Y) _Generic((X)+(Y),\ int: div,\
long: ldiv,\
long long: lldiv)((X), (Y)) auto z = div(x, y);
auto q = z.quot; auto r = z.rem;
/*     initializer:
initializer-list:
designation: designator-list: designator:
{ initializer-list }
{ initializer-list, }
assignment-expression braced-initializer
designationopt initializer
initializer-list , designationopt initializer
designator-list = designator
designator-list designator [ constant-expression ]*/
for (auto i = j; i < 2*j; ++i) { // ...
}
//           . identifier
//  An empty brace pair ({}) is called an empty initializer and is referred to as empty initialization.
//  Constraints
//  No initializer shall attempt to provide a value for an object not contained within the entity being initialized.
//  The type of the entity to be initialized shall be an array of unknown size or a complete object type. An entity of variable length array type shall not be initialized except by an empty initializer. An array of unknown size shall not be initialized by an empty initializer.
//  All the expressions in an initializer for an object that has static or thread storage duration or is declared with the constexpr storage-class specifier shall be constant expressions or string literals.
//  If the declaration of an identifier has block scope, and the identifier has external or internal linkage, the declaration shall have no initializer for the identifier.
//  If a designator has the form
[ constant-expression ]
then the current object (defined below) shall have array type and the expression shall be an integer
constant expression. If the array is of unknown size, any nonnegative value is valid.
//  If a designator has the form . identifier then the current object (defined below) shall have structure or union type and the identifier shall be the name of a member of that type.
// Semantics
//  An initializer specifies the initial value stored in an object. For objects with atomic type additional restrictions apply, see 7.17.2 and 7.17.8.
//  Except where explicitly stated otherwise, for the purposes of this subclause unnamed members of objects of structure and union type do not participate in initialization. Unnamed members of structure objects have indeterminate representation even after initialization.
//  If an object that has automatic storage duration is initialized with an empty initializer, its value is the same as the initialization of a static storage duration object. Otherwise, if an object that has automatic storage duration is not initialized explicitly, its representation is indeterminate. If an object that has static or thread storage duration is not initialized explicitly, or is initialized with an empty initializer, then default initialization:
// — if it has pointer type, it is initialized to a null pointer;
// — if it has decimal floating type, it is initialized to positive zero, and the quantum exponent is implementation-defined178) ;
// — if it has arithmetic type, and it does not have decimal floating type, it is initialized to (positive or unsigned) zero;
// — if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;
// — if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;
//  The initializer for a scalar shall be a single expression, optionally enclosed in braces, or it shall be an empty initializer. If the initializer is the empty initializer, the initial value is the same as the initialization of a static storage duration object. Otherwise, the initial value of the object is that of the expression (after conversion); the same type constraints and conversions as for simple assignment apply, taking the type of the scalar to be the unqualified version of its declared type.
//  The rest of this subclause deals with initializers for objects that have aggregate or union type. 178)A representation with all bits zero results in a decimal floating-point zero with the most negative exponent.
//  The initializer for a structure or union object that has automatic storage duration shall be either an initializer list as described below, or a single expression that has compatible structure or union type. In the latter case, the initial value of the object, including unnamed members, is that of the expression.
//  An array of character type may be initialized by a character string literal or UTF-8 string literal, optionally enclosed in braces. Successive bytes of the string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.
//  An array with element type compatible with a qualified or unqualified version of wchar_t, char16_t , or char32_t may be initialized by a wide string literal with the corresponding encoding prefix (L, u, or U, respectively), optionally enclosed in braces. Successive wide characters of the wide string literal (including the terminating null wide character if there is room or if the array is of unknown size) initialize the elements of the array.
//  Otherwise, the initializer for an object that has aggregate or union type shall be a brace-enclosed list of initializers for the elements or named members.
// Each brace-enclosed initializer list has an associated current object. When no designations are present, subobjects of the current object are initialized in order according to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union.179) In contrast, a designation causes the following initializer to begin initialization of the subobject described by the designator. Initialization then continues forward in order, beginning with the next subobject after that described by the designator.180)
//  Each designator list begins its description with the current object associated with the closest sur- rounding brace pair. Each item in the designator list (in order) specifies a particular member of its current object and changes the current object for the next designator (if any) to be that member.181) The current object that results at the end of the designator list is the subobject to be initialized by the following initializer.
//  The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject;182) all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.
//  If the aggregate or union contains elements or members that are aggregates or unions, these rules apply recursively to the subaggregates or contained unions. If the initializer of a subaggregate or contained union begins with a left brace, the initializers enclosed by that brace and its matching right brace initialize the elements or members of the subaggregate or the contained union. Otherwise, only enough initializers from the list are taken to account for the elements or members of the subaggregate or the first member of the contained union; any remaining initializers are left to initialize the next element or member of the aggregate of which the current subaggregate or contained union is a part.
//  If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
//  If an array of unknown size is initialized, its size is determined by the largest indexed element with an explicit initializer. The array type is completed at the end of its initializer list.
//  The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified.183)
// 179)If the initializer list for a subaggregate or contained union does not begin with a left brace, its subobjects are initialized as usual, but the subaggregate or contained union does not become the current object: current objects are associated only with brace-enclosed initializer lists.
// 180)After a union member is initialized, the next object is not the next member of the union; instead, it is the next subobject of an object containing the union.
// 181)Thus, a designator can only specify a strict subobject of the aggregate or union that is associated with the surrounding brace pair. Note, too, that each separate designator list is independent.
// 182)Any initializer for the subobject which is overridden and so not used to initialize that subobject might not be evaluated at all.
// 183)In particular, the evaluation order need not be the same as the order of subobject initialization.
//  EXAMPLE 1 Provided that <complex.h> has been #included, the declarations define and initialize i with the value 3 and c with the value 5.0 + i3.0.
//  EXAMPLE 2 The declaration
int x[] = { 1, 3, 5 };
// defines and initializes x as a one-dimensional array object that has three elements, as no size was specified and there are three initializers.
//  EXAMPLE 3 The declaration
is a definition with a fully bracketed initialization: 1, 3, and 5 initialize the first row of y (the array object y[0]), namely y[0][0], y[0][1], and y[0][2]. Likewise the next two lines initialize y[1] and y[2]. The initializer ends early, so y[3] is initialized with zeros. Precisely the same effect could have been achieved by
The initializer for y[0] does not begin with a left brace, so three items from the list are used. Likewise the next three are taken successively for y[1] and y[2].
//  EXAMPLE 4 The declaration
initializes the first column of z as specified and initializes the rest with zeros.
// EXAMPLE 5 The declaration
struct { int a[3], b; } w[] = { { 1 }, 2 };
is a definition with an inconsistently bracketed initialization. It defines an array with two element structures: w[0].a[0] is 1 and w[1].a[0] is 2; all the other elements are zero.
//  EXAMPLE 6 The declaration
contains an incompletely but consistently bracketed initialization. It defines a three-dimensional ar- ray object: q[0][0][0] is 1, q[1][0][0] is 2, q[1][0][1] is 3, and 4, 5, and 6 initialize q[2][0][0], q[2][0][1], and q[2][1][0], respectively; all the rest are zero. The initializer for q[0][0] does not begin with a left brace, so up to six items from the current list could be used. There is only one,
         int i = 3.5;
double complex c = 5 + 3 * I;
                              int y[4][3] = {
{ 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 },
};
                             int y[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
                     int z[4][3] = {
{ 1 }, { 2 }, { 3 }, { 4 }
};
                                  short q[4][3][2] = { { 1 },
        { 2, 3 },
{ 4, 5, 6 }
        };
// so the values for the remaining five elements are initialized with zero. Likewise, the initializers for q[1][0] and q[2][0] do not begin with a left brace, so each uses up to six items, initializing their respective two-dimensional subaggregates. If there had been more than six items in any of the lists, a diagnostic message would have been issued. The same initialization result could have been achieved by:
or by:
        short q[4][3][2] = {
1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0,
4, 5, 6 };
                        short q[4][3][2] = { {
{ 1 }, },
{
{ 2, 3 }, },
{
{ 4, 5 },
{ 6 }, }
                                 };
 //    in a fully bracketed form.
//  Note that the fully bracketed and minimally bracketed forms of initialization are, in general, less likely to cause confusion.
//  EXAMPLE 7 One form of initialization that completes array types involves typedef names. Given the declaration
typedef int A[]; // OK - declared with block scope
the declaration
A a = { 1, 2 }, b = { 3, 4, 5 };
// is identical to
int a[] = { 1, 2 }, b[] = { 3, 4, 5 };
// due to the rules for incomplete types.
//  EXAMPLE 8 The declaration
char s[] = "abc", t[3] = "abc";
defines "plain" char array objects s and t whose elements are initialized with character string literals. This declaration is identical to
The contents of the arrays are modifiable. On the other hand, the declaration
char *p = "abc";
                                                        char s[] = { a, b, c, ’\0 }, t[] = { a, b, c };
// defines p with type "pointer to char" and initializes it to point to an object with type "array of char" with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.
//  EXAMPLE 9 Arrays can be initialized to correspond to the elements of an enumeration by using designators:
// EXAMPLE 10 Structure members can be initialized to nonzero values without depending on their order:
div_t answer = {.quot = 2, .rem = -1 };
//  EXAMPLE 11 Designators can be used to provide explicit initialization when unadorned initializer lists might be misunderstood:
//  EXAMPLE 12
struct T { int k;
int l; };
struct S { int i;
struct T t;
};
struct T x = {.l = 43, .k = 42, };
void f(void) {
struct S l = { 1, .t = x, .t.l = 41, };
}
// The value of l.t.k is 42, because implicit initialization does not override explicit initialization.
//  EXAMPLE 13 Space can be "allocated" from both ends of an array by using a single designator:
//  In the above, if MAX is greater than ten, there will be some zero-valued elements in the middle; if it is less than ten, some of the values provided by the first five initializers will be overridden by the second five.
//  EXAMPLE 14 Any member of a union can be initialized: union { /* ... */ } u = {.any_member = 42 };
// Forward references: common definitions <stddef.h> (7.21).
    enum { member_one, member_two }; const char *nm[] = {
         [member_two] = "member two",
[member_one] = "member one",
            };
                          struct { int a[3], b; } w[] =
{ [0].a = {1}, [1].a[0] = 2 };
                          int a[MAX] = {
1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
};
// 6.7.11 Static assertions
// Syntax
//  static_assert-declaration:
static_assert ( constant-expression , string-literal ) ;
static_assert ( constant-expression ) ;
// Constraints
//  The constant expression shall compare unequal to 0.
// Semantics
//  The constant expression shall be an integer constant expression. If the value of the constant expres- sion compares unequal to 0, the declaration has no effect. Otherwise, the constraint is violated and the implementation shall produce a diagnostic message which should include the text of the string literal, if present.
// Forward references: diagnostics (7.2). 6.7.12 Attributes
//  Attributes specify additional information for various source constructs such as types, variables, identifiers, or blocks. They are identified by an attribute token, which can either be a attribute prefixed token (for implementation-specific attributes) or a standard attribute specified by an identifier (for attributes specified in this document).
//  Support for any of the standard attributes specified in this document is implementation-defined and optional. For an attribute token (including an attribute prefixed token) not specified in this document, the behavior is implementation-defined. Any attribute token that is not supported by the implementation is ignored.
//  Attributes are said to appertain to some source construct, identified by the syntactic context where they appear, and for each individual attribute, the corresponding clause constrains the syntactic context in which this appertainance is valid. The attribute specifier sequence appertaining to some source construct shall contain only attributes that are allowed to apply to that source construct.
//  In all aspects of the language, a standard attribute specified by this document as an identifier attr and an identifier of the form __attr__ shall behave the same when used as an attribute token, except for the spelling.184)
// Recommended practice
//  It is recommended that implementations support all standard attributes as defined in this document.
// 6.7.12.1 General
// Syntax
//  attribute-specifier-sequence:
// attribute-specifier-sequenceopt attribute-specifier
// attribute-specifier: attribute-list:
// attribute: attribute-token:
// [ [ attribute-list ] ] attributeopt
// attribute-list , attributeopt
// attribute-token attribute-argument-clauseopt
// standard-attribute attribute-prefixed-token
//  184)Thus, the attributes [[nodiscard]] and [[__nodiscard__]] can be freely interchanged. Implementations are encour- aged to behave similarly for attribute tokens (including attribute prefixed tokens) they provide.
// standard-attribute: identifier
// attribute-prefixed-token:
// attribute-prefix :: identifier
// attribute-prefix:
// identifier attribute-argument-clause:
// ( balanced-token-sequenceopt ) balanced-token-sequence:
// balanced-token:
// Constraints
// balanced-token
balanced-token-sequence balanced-token
// ( balanced-token-sequenceopt ) [ balanced-token-sequenceopt ] { balanced-token-sequenceopt }
// any token other than a parenthesis, a bracket, or a brace
//  The identifier in a standard attribute shall be one of:
deprecated maybe_unused noreturn fallthrough nodiscard _Noreturn
// Semantics unsequenced reproducible
//  An attribute specifier that contains no attributes has no effect. The order in which attribute tokens appear in an attribute list is not significant. If a keyword (6.4.1) that satisfies the syntactic require- ments of an identifier (6.4.2) is contained in an attribute token, it is considered an identifier. A strictly conforming program using a standard attribute remains strictly conforming in the absence of that attribute.185)
//  NOTE 1 For each standard attribute, the form of the balanced token sequence, if any, will be specified. Recommended Practice
//  Each implementation should choose a distinctive name for the attribute prefix in an attribute prefixed token. Implementations should not define attributes without an attribute prefix unless it is a standard attribute as specified in this document.
//  EXAMPLE 1 Suppose that an implementation chooses the attribute prefix hal and provides specific attributes named daisy and rosie. Then all the following declarations should be equivalent aside from the spelling:
// These use the alternate spelling that is required for all standard attributes and recommended for prefixed attributes. These may be better-suited for use in header files, where the use of the alternate spelling avoids naming conflicts with user-provided macros.
// 185)Standard attributes specified by this document can be parsed but ignored by an implementation without changing the semantics of a correct program; the same is not true for attributes not specified by this document.
         [[deprecated, hal::daisy]] double nine1000(double); [[deprecated]] [[hal::daisy]] double nine1000(double); [[deprecated]] double nine1000 [[hal::daisy]] (double);
                [[__deprecated__, __hal__::__daisy__]] double nine1000(double); [[__deprecated__]] [[__hal__::__daisy__]] double nine1000(double); [[__deprecated__]] double nine1000 [[__hal__::__daisy__]] (double);
//  EXAMPLE 2 For the same implementation, the following two declarations are equivalent, because
the ordering inside attribute lists is not important.
On the other hand the following two declarations are not equivalent, because the ordering of different attribute specifiers may affect the semantics.
// 6.7.12.2 The nodiscard attribute
// Constraints
//  The nodiscard attribute shall be applied to the identifier in a function declaration or to the definition of a structure, union, or enumeration type. If an attribute argument clause is present, it shall have the form:
( string-literal) Semantics
//  The __has_c_attribute conditional inclusion expression (6.10.1) shall return the value 202003L when given nodiscard as the pp-tokens operand.
//  A name or entity declared without the nodiscard attribute can later be redeclared with the attribute and vice versa. An entity is considered marked after the first declaration that marks it.
Recommended Practice
//  A nodiscard call is a function call expression that calls a function previously declared with attribute nodiscard, or whose return type is a structure, union, or enumeration type marked with attribute nodiscard. Evaluation of a nodiscard call as a void expression (6.8.3) is discouraged unless explicitly cast to void. Implementations are encouraged to issue a diagnostic in such cases. This is typically because immediately discarding the return value of a nodiscard call has surprising consequences.
//  The diagnostic message should include text provided by the string literal within the attribute argument clause of any nodiscard attribute applied to the name or entity.
//  EXAMPLE 1
A diagnostic for the call to enable_missile_safety_mode is encouraged.
//  EXAMPLE 2
No diagnostic for the call to important_func is encouraged despite the value of i not being used.
//  EXAMPLE 3
[[nodiscard("must check armed state")]]
        [[hal::daisy, hal::rosie]] double nine999(double); [[hal::rosie, hal::daisy]] double nine999(double);
               [[hal::daisy]] [[hal::rosie]] double nine999(double);
[[hal::rosie]] [[hal::daisy]] double nine999(double); // may have different semantics
           struct [[nodiscard]] error_info { /*...*/ };
struct error_info enable_missile_safety_mode(void); void launch_missiles(void);
void test_missiles(void) {
             enable_missile_safety_mode();
launch_missiles();
         }
        [[nodiscard]] int important_func(void); void call(void) {
       int i = important_func();
      }
bool arm_detonator(int within);
void call(void) { arm_detonator(3);
                     detonate();
    }
//     A diagnostic for the call to arm_detonator using the string literal "must check armed state" from the attribute argument clause is encouraged.
// 6.7.12.3 The maybe_unused attribute
// Constraints
//  The maybe_unused attribute shall be applied to the declaration of a structure, a union, a typedef name, a variable, a structure or union member, a function, an enumeration, an enumerator, or a label. No attribute argument clause shall be present.
Semantics
//  The maybe_unused attribute indicates that a name or entity is possibly intentionally unused.
//  The __has_c_attribute conditional inclusion expression (6.10.1) shall return the value 202106L when given maybe_unused as the pp-tokens operand. A name or entity declared without the maybe_unused attribute can later be redeclared with the attribute and vice versa. An entity is considered marked with the attribute after the first declaration that marks it.
// Recommended Practice
//  For an entity marked maybe_unused, implementations are encouraged not to emit a diagnostic that the entity is unused, or that the entity is used despite the presence of the attribute.
//  EXAMPLE Implementations are encouraged not to diagnose that j is unused, even if NDEBUG is defined.
// 6.7.12.4 The deprecated attribute
// Constraints
// The deprecated attribute shall be applied to the declaration of a structure, a union, a typedef name, a variable, a structure or union member, a function, an enumeration, or an enumerator.
//  If an attribute argument clause is present, it shall have the form:
( string-literal) Semantics
//  The deprecated attribute can be used to mark names and entities whose use is still allowed, but is discouraged for some reason. 186)
//  The __has_c_attribute conditional inclusion expression (6.10.1) shall return the value 201904L when given deprecated as the pp-tokens operand.
//  A name or entity declared without the deprecated attribute can later be redeclared with the attribute and vice versa. An entity is considered marked with the // attribute after the first declaration that marks it.
// 186)In particular, deprecated is appropriate for names and entities that are obsolescent, insecure, unsafe, or otherwise unfit for purpose.
    [[maybe_unused]] void f([[maybe_unused]] int i) { [[maybe_unused]] int j = i + 100; assert(j);
}
// Recommended Practice
//  Implementations should use the deprecated attribute to produce a diagnostic message in case the program refers to a name or entity other than to declare it, after a declaration that specifies the attribute, when the reference to the name or entity is not within the context of a related deprecated entity. The diagnostic message should include text provided by the string literal within the attribute argument clause of any deprecated attribute applied to the name or entity.
// EXAMPLE
struct [[deprecated]] S { int a;
};
enum [[deprecated]] E1 { one
};
enum E2 {
two [[deprecated("use ’three’ instead")]], three
};
[[deprecated]] typedef int Foo;
void f1(struct S s) { // Diagnose use of S
int i = one; // Diagnose use of E1
int j = two; // Diagnose use of two: "use ’three’ instead" int k = three;
Foo f; // Diagnose use of Foo
}
[[deprecated]] void f2(struct S s) { int i = one;
int j = two; int k = three; Foo f;
}
struct [[deprecated]] T { Foo f;
struct S s;
};
Implementations are encouraged to diagnose the use of deprecated entities within a context which is not itself deprecated, as indicated for function f1, but not to diagnose within function f2 and struct T,astheyarethemselvesdeprecated.
// 6.7.12.5 The fallthrough attribute
// Constraints
//  The attribute token fallthrough shall only appear in an attribute declaration (6.7); such a dec- laration is a fallthrough declaration. No attribute argument clause shall be present. A fallthrough declaration may only appear within an enclosing switch statement (6.8.4.2). The next block item (6.8.2) that would be encountered after a fallthrough declaration shall be a case label or default label associated with the smallest enclosing switch statement.
// Semantics
//  The __has_c_attribute conditional inclusion expression (6.10.1) shall return the value 201910L when given fallthrough as the pp-tokens operand.
//  Recommended Practice
//  The use of a fallthrough declaration is intended to suppress a diagnostic that an implementation might otherwise issue for a case or default label that is reachable from another case or default label along some path of execution. Implementations are encouraged to issue a diagnostic if a fallthrough declaration is not dynamically reachable.
//  EXAMPLE
         void f(int n) {
void g(void), h(void), i(void);
switch (n) {
case 1: /* diagnostic on fallthrough discouraged */ 
case 2:
g();
[[fallthrough]];
case 3: /* diagnostic on fallthrough discouraged */
h();
case 4: /* fallthrough diagnostic encouraged */
                                        i();
[[fallthrough]]; /* constraint violation */
        } }
// 6.7.12.6 The noreturn and _Noreturn attributes
// Description
//  When _Noreturn is used as an attribute token (instead of a function specifier), the constraints and semantics are identical to that of the noreturn attribute token. Use of _Noreturn as an attribute token is an obsolescent feature187).
// Constraints
//  The noreturn attribute shall be applied to the identifier in a function declaration. No attribute argument clause shall be present.
// Semantics
//  The first declaration of a function shall specify the noreturn attribute if any declaration of that function specifies the noreturn attribute. If a function is declared with the noreturn attribute in one translation unit and the same function is declared without the noreturn attribute in another translation unit, the behavior is undefined.
//  If a function f is called where f was previously declared with the noreturn attribute and f eventually returns, the behavior is undefined.
//  The __has_c_attribute conditional inclusion expression (6.10.1) shall return the value 202202L when given noreturn as the pp-tokens operand.
Recommended Practice
//  The implementation should produce a diagnostic message for a function declared with a noreturn attribute that appears to be capable of returning to its caller.
//  EXAMPLE
187)[[_Noreturn]] and [[noreturn]] are equivalent attributes to support code that includes <stdnoreturn.h>, because that header defines noreturn as a macro that expands to _Noreturn.
         [[noreturn]] void f(void) { abort(); // ok
}
[[noreturn]] void g(int i) { // causes undefined behavior if i <= 0 if (i > 0) abort();
}
       [[noreturn]] int h(void);
//     Implementations are encouraged to diagnose the definition of g() because it is capable of returning to its caller. Implementations are similarly encouraged to diagnose the declaration of h() because it appears capable of returning to its caller due to the non-void return type.
// 6.7.12.7 Standard attributes unsequenced and reproducible for function types
// Constraints
//  The identifier in a standard function type attribute shall be one of: unsequenced reproducible
//  An attribute for a function type shall be applied to a function declarator188) or to a type specifier that has a function type. The corresponding attribute is a property of the referred function type.189) No attribute argument clause shall be present.
Description
//  The main purpose of the function type properties and attributes defined in this clause is to provide the translator with information about the access of objects by a function such that certain properties of function calls can be deduced; the properties distinguish read operations (stateless and inde- pendent) and write operations (effectless, idempotent and reproducible) or a combination of both (unsequenced). Although semantically attached to a function type, the attributes described are not part of the prototype of a such annotated function, and redeclarations and conversions that drop such an attribute are valid and constitute compatible types. Conversely, if a definition that does not have the asserted property is accessed by a function declaration or a function pointer with a type that has the attribute, the behavior is undefined.190)
//  To allow reordering of calls to functions as they are described here, possible access to objects with a lifetime that starts before or ends after a call has to be restricted; effects on all objects that are accessed during a function call are restricted to the same thread as the call and the based-on relation between pointer parameters and lvalues (6.7.3.1) models the fact that objects do not change inadvertently during the call. In the following, an operation is said to be sequenced during a function call if it is sequenced after the start of the function call191) and before the call terminates. An object definition of an object X in a function f escapes if an access to X happens while no call to f is active. An object is local to a call to a function f if its lifetime starts and ends during the call or if it is defined by f but does not escape. A function call and an object X synchronize if all accesses to X that are not sequenced during the call happen before or after the call. Execution state that is described in the library clause, such as the floating-point environment, conversion state, locale, input/output streams, external files or errno account as objects; operations that allow to query this state, even indirectly, account as lvalue conversions, and operations that allow to change this state account as store operations.
//  A function definition f is stateless if any definition of an object of static or thread storage duration in f or in a function that is called by f is const but not volatile qualified.
//  An object X is observed by a function call if both synchronize, if X is not local to the call, if X has a lifetime that starts before the function call and if an access of X is sequenced during the call; the last value of X, if any, that is stored before the call is said to be the value of X that is observed by the call. A function pointer value f is independent if for any object X that is observed by some call to f
// 188)That is, they appear in the attributes right after the closing parenthesis of the parameter list, independently if the function type is, for example, used directly to declare a function or if it is used in a pointer to function type.
189)If several declarations of the same function or function pointer are visible, regardless whether an attribute is present at several or just one of the declarators, it is attached to the type of the corresponding function definition, function pointer object, or function pointer value.
// 190)That is, the fact that a function has one of these properties is in general not determined by the specification of the translation unit in which it is found; other translation units and specific run time conditions also condition the possible assertion of the properties.
// 191)The initializations of the parameters is sequenced during the function call.
// through an lvalue that is not based on a parameter of the call, then all accesses to X in all calls to f during the same program execution observe the same value; otherwise if the access is based on a pointer parameter, there shall be a unique such pointer parameter P such that any access to X shall be to an lvalue that is based on P . A function definition is independent if the derived function pointer value is independent.
//  A store operation to an object X that is sequenced during a function call such that both synchronize is said to be observable if X is not local to the call, if the lifetime of X ends after the call, if the stored value is different from the value observed by the call, if any, and if it is the last value written before the termination of the call. An evaluation of a function call192) is effectless if any store operation that is sequenced during the call is the modification of an object that synchronizes with the call; if additionally the operation is observable, there shall be a unique pointer parameter P of the function such that any access to X shall be to an lvalue that is based on P . A function pointer value f is effectless if any evaluation of a function call that calls f is effectless. A function definition is effectless if the derived function pointer value is effectless.
//  An evaluation E is idempotent if a second evaluation of E can be sequenced immediately after the original one without changing the resulting value, if any, or the observable state of the execution. A function pointer value f is idempotent if any evaluation of a function call193) that calls f is idempotent. A function definition is idempotent if the derived function pointer value is idempotent.
//  A function is reproducible if it is effectless and idempotent; it is unsequenced if it is stateless, effectless, idempotent and independent.194)
//  NOTE 1 The synchronization requirements with respect to any accessed object X for the independence of functions provide boundaries up to which a function call may safely be reordered without changing the semantics of the program. If X is const but not volatile qualified the reordering is unconstrained. If it is an object that is conditioned in an initialization phase, for a single threaded program a synchronization is provided by the sequenced before relation and the reordering may, in principle, move the call just after the initialization. For a multi-threaded program, synchronization guarantees can be given by calls to synchronizing functions of the <threads.h> header or by an appropriate call to atomic_thread_fence at the end of the initialization phase. If a function is known to be independent or effectless, adding restrict qualifications to the declarations of all pointer parameters does not change the semantics of any call. Similarly, changing the memory order to memory_order_relaxed for all atomic operations during a call to such a function preserves semantics.
//  NOTE 2 In general the functions provided by the <math.h> header do not have the properties that are defined above; many of them change the floating-point state or errno when they encounter an error (so they have observable side effects) and the results of most of them depend on execution wide state such as the rounding direction mode (so they are not independent). Whether a particular C library function is reproducible or unsequenced additionally often depends on properties of the implementation, such as implementation-defined behavior for certain error conditions.
Recommended Practice
12 If possible, it is recommended that implementations diagnose if an attribute of this clause is applied to a function definition that does not have the corresponding property. It is recommended that appli- cations that assert the independent or effectless properties for functions qualify pointer parameters with restrict.
Forward references: errors <errno.h> (7.5), floating-point environment <fenv.h> (7.6), localiza- tion <locale.h> (7.11), mathematics <math.h> (7.12), fences (7.17.4), input/output <stdio.h> (7.23), threads <threads.h> (7.28), extended multibyte and wide character utilities <wchar.h> (7.31).
// 6.7.12.7.1 The reproducible type attribute
// Description
//  The reproducible type attribute asserts that a function or pointed-to function with that type is reproducible.
// 192)This considers the evaluation of the function call itself, not the evaluation of a full function call expression. Such an evaluation is sequenced after all evaluations that determine f and the call arguments, if any, have been performed.
// 193)This considers the evaluation of the function call itself, not the evaluation of a full function call expression. Such an evaluated is sequenced after all evaluations that determine f and the call arguments, if any, have been performed.
// 194)A function call of an unsequenced function can be executed as early as the function pointer value, the values of the arguments and all objects that are accessible through them, and all values of globally accessible state have been determined, and it can be executed as late as the arguments and the objects they possibly target are unchanged and as any of its return value or modified pointed-to arguments are accessed.
//  The __has_c_attribute conditional inclusion expression (6.10.1) shall return the value 202207L
when given reproducible as the pp-tokens operand.
//  EXAMPLE 1 The attribute in the following function declaration asserts that two consecutive calls to the function will result in the same return value. Changes to the abstract state during the call are possible as long as they are not observable, but no other side effects will occur. Thus the function definition may for example use local objects of static or thread storage duration to keep track of the arguments for which the function has been called and cache their computed return values.
size_t hash(char const[static 32]) [[reproducible]];
// 6.7.12.7.2 The unsequenced type attribute
// Description
//  The unsequenced type attribute asserts that a function or pointed-to function with that type is unsequenced.
//  The __has_c_attribute conditional inclusion expression (6.10.1) shall return the value 202207L when given unsequenced as the pp-tokens operand.
//  NOTE 1 The unsequenced type attribute asserts strong properties for the such typed function, in particular that certain sequencing requirements for function calls can be relaxed without affecting the state of the abstract machine. Thereby, calls to such functions are natural candidates for optimization techniques such as common subexpression elimination, local memoization or lazy evaluation.
//  NOTE 2 A proof of validity of the annotation of a function type with the unsequenced attribute may depend on the property if a derived function pointer escapes the translation unit or not. For a function with internal linkage where no function pointer escapes the translation unit, all calling contexts are known and it is possible, in principle, to prove that no control flow exists such that a library function is called with arguments that trigger an exceptional condition. For a function with external linkage such a proof may not be possible and the use of such a function then has to ensure that no exceptional condition results from the provided arguments.
//  NOTE 3 The unsequenced property does not necessarily imply that the function is reentrant or that calls can be executed concurrently. This is because an unsequenced function can read from and write to objects of static storage duration, as long as no change is observable after a call terminates.
//  EXAMPLE 1 The attribute in the following function declaration asserts that it doesn’t depend on any modifiable state of the abstract machine. Calls to the function can be executed out of sequence before the return value is needed and two calls to the function with the same argument value will result in the same return value.
bool tendency(signed char) [[unsequenced]];
Therefore such a call for a given argument value needs only to be executed once and the returned value can be reused when appropriate. For example, calls for all possible argument values can be executed during program startup and tabulated.
//  EXAMPLE 2 The attribute in the following function declaration asserts that it doesn’t depend on any modifiable state of the abstract machine. Within the same thread, calls to the function can be executed out of sequence before the return value is needed and two calls to the function will result in the same pointer return value. Therefore such a call needs only to be executed once in a given thread and the returned pointer value can be reused when appropriate. For example, a single call can be executed during thread startup and the return value p and the value of the object *p of type toto constcanbecached.
//  EXAMPLE 3 The unsequenced property of a function f can be locally asserted within a function g that uses it. For example the library function sqrt is in generally not unsequenced because a negative argument will raise a domain error and because the result may depend on the rounding mode. Nevertheless in contexts similar to the following function a user can prove that it will not be called with invalid arguments, and, that the floating-point environment has the same value for all calls.
                                typedef struct toto toto;
toto const* toto_zero(void) [[unsequenced]];
#include <math.h> 
#include <fenv.h>
inline double distance (double const x[static 2]) [[reproducible]] { #pragma FP_CONTRACT OFF
#pragma FENV_ROUND FE_TONEAREST
// We assert that sqrt will not be called with invalid arguments // and the result only depends on the argument value.
extern typeof(sqrt) [[unsequenced]] sqrt;
return sqrt(x[0]*x[0] + x[1]*x[1]);
}
// The function distance potentially has the side effect of changing the floating-point environment. Nevertheless the floating environment is thread local, thus a change to that state outside the function is sequenced with the change within and additionally the observed value is restored when the function returns. Thus this side effect is not observable for a caller. Overall the function distance is stateless, effectless and idempotent and in particular it is reproducible as the attribute indicates. Because the function can be called in a context where the floating-point environment has different state, distance is not independent and thus it is also not unsequenced. Nevertheless, adding an unsequenced attribute where this is justified may introduce optimization opportunities.
double g (double y[static 1], double const x[static 2]) {
// We assert that distance will not see different states of the floating // point environment.
extern double distance (double const x[static 2]) [[unsequenced]];
y[0] = distance(x);
// ...
return distance(x); // replacement by y[0] is valid
} 
int main() {
//    PR3(st.a,st.b,st.c,d);
    printf("%s\n", n3054);
    return EXIT_SUCCESS;
}

編纂・実行結果(compile and go)

bash

検討事項(agenda)

コンパイルエラーを取るか、コンパイルエラーの理由を解説する。

応用例1 MISRA C/C++

MISRA C まとめ #include

MISRA C++ 5-0-16

応用例2 CERT C/C++

SEI CERT C++ Coding Standard AA. Bibliography 確認中。

MISRA C/C++, AUTOSAR C++, CERT C/C++とC/C++工業標準をコンパイルする

自己参考資料(self reference)

関連する自己参照以外は、こちらの先頭に移転。

C言語(C++)に対する誤解、曲解、無理解、爽快。

C2011コンパイル一覧@researchmap

https://researchmap.jp/jownvh0ye-1797580/#_1797580

[C][C++]の国際規格案の例題をコンパイルするときの課題7つ。

C Puzzle Bookの有り難み5つ、C言語規格及びCコンパイラの特性を認識

dockerにclang

docker gnu(gcc/g++) and llvm(clang/clang++)

コンパイル用shell script C版(clangとgcc)とC++版(clang++とg++)

astyle 使ってみた

<この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。>

文書履歴(document history)

ver. 0.01 初稿  20221021

最後までおよみいただきありがとうございました。

いいね 💚、フォローをお願いします。

Thank you very much for reading to the last sentence.

Please press the like icon 💚 and follow me for your happy life.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?