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.5 Expressions, CN3054:2022 (7) p71.c

Last updated at Posted at 2022-10-21

はじめに(Introduction)

N3054 Working Draft, Standard for Programming Language C

http://www.open-std.org/jtc1/sc22/wg14/docs/papers/2022/n3054.pdf
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3054.pdf

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.5 Expressions, CN3054:2022 (7) p71.c

算譜(source code)

p71.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.5 Expressions, CN3054:2022 (7) p71.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.5 Expressions
//  An expression is a sequence of operators and operands that specifies computation of a value, or that designates an object or a function, or that generates side effects, or that performs a combination thereof. The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.
//  If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.95)
//  The grouping of operators and operands is indicated by the syntax.96) Except as specified later, side effects and value computations of subexpressions are unsequenced.97)
//  Some operators (the unary operator ~, and the binary operators <<, >>, &, ^, and |, collectively described as bitwise operators) are required to have operands that have integer type. These operators yield values that depend on the internal representations of integers, and have implementation- defined and undefined aspects for signed types.
//  If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.
//  The effective type of an object for an access to its stored value is the declared type of the object, if any.98) If a value is stored into an object having no declared type through an lvalue having a type that is not a non-atomic character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.
//  An object shall have its stored value accessed only by an lvalue expression that has one of the following types:99)
// — a type compatible with the effective type of the object,
// — a qualified version of a type compatible with the effective type of the object,
// — a type that is the signed or unsigned type corresponding to the effective type of the object,
// 95)This paragraph renders undefined statement expressions such as while allowing
// 96)The syntax specifies the precedence of operators in the evaluation of an expression, which is the same as the order of the major subclauses of this subclause, highest precedence first. Thus, for example, the expressions allowed as the operands of the binary + operator (6.5.6) are those expressions defined in 6.5.1 through 6.5.6. The exceptions are cast expressions (6.5.4) as operands of unary operators (6.5.3), and an operand contained between any of the following pairs of operators: grouping parentheses () (6.5.1), subscripting brackets [] (6.5.2.1), function-call parentheses () (6.5.2.2), and the conditional operator ?: (6.5.15). Within each major subclause, the operators have the same precedence. Left- or right-associativity is indicated in each subclause by the syntax for the expressions discussed therein.
// 97)In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations.
// 98)Allocated objects have no declared type.
// 99)The intent of this list is to specify those circumstances in which an object can or cannot be aliased.
i = ++i + 1;
a[i++] = i;
i = i + 1;
a[i] = i;
//  — a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
// — an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
// — a character type.
//  A floating expression may be contracted, that is, evaluated as though it were a single opera- tion, thereby omitting rounding errors implied by the source code and the expression evalua- tion method.100) The FP_CONTRACT pragma in <math.h> provides a way to disallow contracted expressions. Otherwise, whether and how expressions are contracted is implementation-defined.101)
//  Operators involving decimal floating types are evaluated according to the semantics of IEC 60559, including production of results with the preferred quantum exponent as specified in IEC 60559.
// Forward references: the FP_CONTRACT pragma (7.12.2), copying functions (7.26.2).
// 6.5.1 Primary expressions
// Syntax
//  primary-expression: identifier
// constant string-literal
// ( expression ) generic-selection
// Constraints
// The identifier in an identifier primary expression shall have a visible declaration as an ordinary identifier that declares an object or a function.102)
// Semantics
//  An identifier primary expression designating an object is an lvalue. An identifier primary expression designating a function is a function designator.
//  A constant is a primary expression. Its type depends on its form and value, as detailed in 6.4.4.
// A string literal is a primary expression. It is an lvalue with type as detailed in 6.4.5.
//  A parenthesized expression is a primary expression. Its type, value, and semantics are identical to those of the unparenthesized expression.
//  A generic selection is a primary expression. Its type, value, and semantics depend on the selected generic association, as detailed in the following subclause.
// Forward references: declarations (6.7).
// 6.5.1.1 Generic selection
// Syntax
//  generic-selection: generic-assoc-list: _Generic ( assignment-expression , generic-assoc-list ) generic-association
//  100)The intermediate operations in the contracted expression are evaluated as if to infinite range and precision, while the final operation is rounded to the format determined by the expression evaluation method. A contracted expression might also omit the raising of floating-point exceptions.
// 101)This license is specifically intended to allow implementations to exploit fast machine instructions that combine multiple C operators. As contractions potentially undermine predictability, and can even decrease accuracy for containing expressions, their use needs to be well-defined and clearly documented.
// 102)An identifier designating an enumeration constant is a primary expression through the constant production, not the identifier production. generic-assoc-list , generic-association generic-association: type-name : assignment-expression default: assignment-expression
// Constraints
//  A generic selection shall have no more than one default generic association. The type name in a generic association shall specify a complete object type other than a variably modified type. No two generic associations in the same generic selection shall specify compatible types. The type of the controlling expression is the type of the expression as if it had undergone an lvalue conversion,103) array to pointer conversion, or function to pointer conversion. That type shall be compatible with at most one of the types named in the generic association list. If a generic selection has no default generic association, its controlling expression shall have type compatible with exactly one of the types named in its generic association list.
// Semantics
//  The controlling expression of a generic selection is not evaluated. If a generic selection has a generic association with a type name that is compatible with the type of the controlling expression, then the result expression of the generic selection is the expression in that generic association. Otherwise, the result expression of the generic selection is the expression in the default generic association. None of the expressions from any other generic association of the generic selection is evaluated.
//  The type and value of a generic selection are identical to those of its result expression. It is an lvalue, a function designator, or a void expression if its result expression is, respectively, an lvalue, a function designator, or a void expression.
//  EXAMPLE A cbrt type-generic macro could be implemented as follows:
// 7.27 shows how such a macro could be implemented with the required rounding properties.
// 6.5.2 Postfix operators
#define cbrt(X) _Generic((X), \ long double: cbrtl, \ default: cbrt, \ float: cbrtf \
)(X)
//                         Syntax
//  postfix-expression:
// primary-expression
// postfix-expression [ expression ] postfix-expression ( argument-expression-listopt ) postfix-expression .  identifier
// postfix-expression -> identifier
// postfix-expression ++
// postfix-expression --
// compound-literal
// argument-expression-list: assignment-expression
// argument-expression-list , assignment-expression
// 103)An lvalue conversion drops type qualifiers.
// 6.5.2.1 Array subscripting
// Constraints
//  One of the expressions shall have type "pointer to complete object type", the other expression shall have integer type, and the result has type "type".
// Semantics
//  A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2 -th element of E1 (counting from zero).
//  Successive subscript operators designate an element of a multidimensional array object. If E is an n-dimensional array (n ≥ 2) with dimensions i × j × · · · × k, then E (used as other than an lvalue) is converted to a pointer to an (n − 1)-dimensional array with dimensions j × · · · × k. If the unary * operator is applied to this pointer explicitly, or implicitly as a result of subscripting, the result is the referenced (n − 1)-dimensional array, which itself is converted into a pointer if used as other than an lvalue. It follows from this that arrays are stored in row-major order (last subscript varies fastest).
//  EXAMPLE Consider the array object defined by the declaration
int x[3][5];
// Here x is a 3 × 5 array of objects of type int; more precisely, x is an array of three element objects, each of which is an array of five objects of type int. In the expression x[i], which is equivalent to (*((x)+(i))), x is first converted to a pointer to the initial array of five objects of type int. Then i is adjusted according to the type of x, which conceptually entails multiplying i by the size of the object to which the pointer points, namely an array of five int objects. The results are added and indirection is applied to yield an array of five objects of type int. When used in the expression x[i][j], that array is in turn converted to a pointer to the first of the objects of type int, so x[i][j] yields an int.
// Forward references: additive operators (6.5.6), address and indirection operators (6.5.3.2), array declarators (6.7.6.2).
// 6.5.2.2 Function calls
// Constraints
//  The expression that denotes the called function104) shall have type pointer to function returning void or returning a complete object type other than an array type.
//  The number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter
// Semantics
//  A postfix expression followed by parentheses () containing a possibly empty, comma-separated list of expressions is a function call. The postfix expression denotes the called function. The list of expressions specifies the arguments to the function.
//  An argument may be an expression of any complete object type. In preparing for the call to a function, the arguments are evaluated, and each parameter is assigned the value of the corresponding argument.105)
//  If the expression that denotes the called function has type pointer to function returning an object type, the function call expression has the same type as that object type, and has the value determined as specified in 6.8.6.4. Otherwise, the function call has type void.
// 104)Most often, this is the result of converting an identifier that is a function designator.
// 105)A function can change the values of its parameters, but these changes cannot affect the values of the arguments. On the other hand, it is possible to pass a pointer to an object, and the function can then change the value of the object pointed to. A parameter declared to have array or function type is adjusted to have a pointer type as described in 6.7.6.3.
//  The arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type. The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter, if present. The integer promotions are performed on each trailing argument, and trailing arguments that have type float are promoted to double. These are called the default argument promotions. No other conversions are performed implicitly.
//  If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined.
//  There is a sequence point after the evaluations of the function designator and the actual arguments but before the actual call. Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.106)
//  Recursive function calls shall be permitted, both directly and indirectly through any chain of other functions.
// EXAMPLE In the function call (*pf[f1()]) (f2(), f3() + f4()) the functions f1, f2, f3, and f4 can be called in any order. All side effects have to be completed before the function pointed to by pf[f1()] is called.
// Forward references: function declarators (6.7.6.3), function definitions (6.9.1), the return statement (6.8.6.4), simple assignment (6.5.16.1).
// 6.5.2.3 Structure and union members
// Constraints
//  The first operand of the . operator shall have an atomic, qualified, or unqualified structure or union type, and the second operand shall name a member of that type.
//  The first operand of the -> operator shall have type "pointer to atomic, qualified, or unqualified structure" or "pointer to atomic, qualified, or unqualified union", and the second operand shall name a member of the type pointed to.
// Semantics
//  A postfix expression followed by the . operator and an identifier designates a member of a structure or union object. The value is that of the named member,107) and is an lvalue if the first expression is an lvalue. If the first expression has qualified type, the result has the so-qualified version of the type of the designated member.
//  A postfix expression followed by the -> operator and an identifier designates a member of a structure or union object. The value is that of the named member of the object to which the first expression points, and is an lvalue.108) If the first expression is a pointer to a qualified type, the result has the so-qualified version of the type of the designated member.
// Accessing a member of an atomic structure or union object results in undefined behavior.109)
//  One special guarantee is made to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial
// 106)In other words, function executions do not interleave with each other.
// 107)If the member used to read the contents of a union object is not the same as the member last used to store a value in the object the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called type punning). This might be a non-value representation.
// 108)If &E is a valid pointer expression (where & is the address of operator, which generates a pointer to its operand), the expression (&E)->MOS is the same as E.MOS.
// 109)For example, a data race would occur if access to the entire structure or union in one thread conflicts with access to a member from another thread, where at least one access is a modification. Members can be safely accessed using a non-atomic object which is assigned to or from the atomic object.
// sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.
//  EXAMPLE 1 If f is a function returning a structure or union, and x is a member of that structure or union, f().x is a valid postfix expression but is not an lvalue.
//  EXAMPLE 2 In:
// the various members have the types:
// s.i int
// s.ci const int
// cs.i const int
// cs.ci const int
// vs.i volatile int
// vs.ci volatile const int
//  EXAMPLE 3 The following is a valid fragment:
union {
    struct {
        int alltypes;
    } n;
    struct {
        int type;
        int intnode;
    } ni;
    struct {
        int type;
        double doublenode;
    } nf;
} u;
u.nf.type = 1;
u.nf.doublenode = 3.14; /* ... */
if (u.n.alltypes == 1)
    if (sin(u.nf.doublenode) == 0.0) /* ... */
// The following is not a valid fragment (because the union type is not visible within function f):
        struct s {
            int i;
            const int ci;
        };
struct s s;
const struct s cs;
volatile struct s vs;
struct t1 {
    int m;
};
struct t2 {
    int m;
};
int f(struct t1 *p1, struct t2 *p2) {
    if (p1->m < 0) p2->m = -p2->m;
    return p1->m;
}
int g() {
    union {
        struct t1 s1;
        struct t2 s2;
    } u;
    /* ... */
    return f(&u.s1, &u.s2);
// Forward references: address and indirection operators (6.5.3.2), structure and union specifiers (6.7.2.1).
// 6.5.2.4 Postfix increment and decrement operators
// Constraints
//  The operand of the postfix increment or decrement operator shall have atomic, qualified, or unquali- fied real or pointer type, and shall be a modifiable lvalue.
// Semantics
// The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it). See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. The value computation of the result is sequenced before the side effect of updating the stored value of the operand. With respect to an indeterminately sequenced function call, the operation of postfix ++ is a single evaluation. Postfix ++ on an object with atomic type is a read-modify-write operation with memory_order_seq_cst memory order semantics.110)
//  The postfix -- operator is analogous to the postfix ++ operator, except that the value of the operand is decremented (that is, the value 1 of the appropriate type is subtracted from it).
// Forward references: additive operators (6.5.6), compound assignment (6.5.16.2).
// 6.5.2.5 Syntax
// Compound literals compound-literal: ( storage-class-specifiersopt type-name ) braced-initializer storage-class-specifiers: storage-class-specifier storage-class-specifiers storage-class-specifier
// Constraints
//  The type name shall specify a complete object type or an array of unknown size, but not a variable length array type.
//  All the constraints for initializer lists in 6.7.10 also apply to compound literals.
//  If the compound literal is evaluated outside the body of a function and outside of any parameter list, it is associated with file scope; otherwise, it is associated with the enclosing block. Depending on this association, the storage-class specifiers SC (possibly empty)111), type name T, and initializer list, if any, shall be such that they are valid specifiers for an object definition in file scope or block scope,
// 110)Where a pointer to an atomic object can be formed and E has integer type, E++ is equivalent to the following code sequence where T is the type of E: with old being the result of the operation. Special care is necessary if E has floating type; see 6.5.16.2.
// 111)If the storage-class specifiers contain the same storage-class specifier more than once, the following constraint is violated. § 6.5.2.5 Language 77
    T *addr = &E;
    T old = *addr;
    T new;
    do {
        new = old + 1;
    } while (!atomic_compare_exchange_strong(addr, &old, new));
// respectively, of the following form,
    SC typeof(T) ID = { IL };
// where ID is an identifier that is unique for the whole program and where IL is a (possibly empty) initializer list with nested structure, designators, values and types as the initializer list of the compound literal. All the constraints for storage class specifiers in 6.7.1 also apply correspondingly to compound literals.
// Semantics
//  A compound literal provides an unnamed object whose value, type, storage duration and other properties are as if given by the definition syntax in the constraints; if the storage duration is automatic, the lifetime of the instance of the unnamed object is the current execution of the enclosing block.112) If the storage-class specifiers contain other specifiers than constexpr, static, register, or thread_local the behavior is undefined.
//  The value of the compound literal is that of an lvalue corresponding to the unnamed object.
//  All the semantic rules for initializer lists in 6.7.10 also apply to compound literals.113)
//  EXAMPLE 1 Consider the following 2 functions: Here, each call to g creates an unnamed object of type int[27] to determine the variably-modified type of para for the duration of the call. During that determination, a pointer to the object is passed into a call to the function f. If a pointer to the object is kept by f, access to that object is possible during the whole execution of the call to g. The lifetime of the object ends with the end of the call to g; for any access after that, the behavior is undefined.
//  String literals, and compound literals with const-qualified types, need not designate distinct ob- jects.114)
//  EXAMPLE 2 The file scope definition
    int *p = (int []) {
        2, 4
    };
// initializes p to point to the first element of an array of two ints, the first having the value two and the second, four. The expressions in this compound literal are required to be constant. The unnamed object has static storage duration.
//  EXAMPLE 3 In contrast, in p is assigned the address of the first element of an array of two ints, the first having the value
// 112)Note that this differs from a cast expression. For example, a cast specifies a conversion to scalar types or void only, and the result of a cast expression is not an lvalue.
// 113)For example, subobjects without explicit initializers are initialized to zero.
// 114)This allows implementations to share storage for string literals and constant compound literals with the same or overlapping representations.
    int f(int*);
    int g(char * para[f((int[27]) {
                    0,
                })]) {
        /* ... */
        return 0;
    }
    void f(void) {
        int *p;
        /*...*/
        p = (int [2]) {
            *p
        }; /*...*/
    }
//  previously pointed to by p and the second, zero. The expressions in this compound literal need not be constant. The unnamed object has automatic storage duration.
//  EXAMPLE 4 Initializers with designations can be combined with compound literals. Structure objects created using compound literals can be passed to functions without depending on member order: Or, if draw line instead expected pointers to struct point:
//  EXAMPLE 5 A read-only compound literal can be specified through constructions like:
    (const float []) {
        1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6
    }
//  EXAMPLE 6 The following three expressions have different meanings: The first always has static storage duration and has type array of char, but need not be modifiable; the last two have automatic storage duration when they occur within the body of a function, and the first of these two is modifiable.
//  EXAMPLE 7 Like string literals, const-qualified compound literals can be placed into read-only memory and can even be shared. For example, (const char []){"abc"} == "abc" might yield 1 if the literals’ storage is shared.
// EXAMPLE 8 Since compound literals are unnamed, a single compound literal cannot specify a circularly linked object. For example, there is no way to write a self-referential compound literal that could be used as the function argument in place of the named object endless_zeros below:
//  EXAMPLE 9 Each compound literal creates only a single object in a given scope:
    drawline((struct point) {
        .x=1, .y=1
    }, (struct point) {
        .x=3, .y=4
    });
    drawline(&(struct point) {
        .x=1, .y=1
    }, &(struct point) {
        .x=3, .y=4
    });
    "/tmp/fileXXXXXX"
    (char []) {"/tmp/fileXXXXXX"}
    (const char []) {"/tmp/fileXXXXXX"}
    struct int_list {
        int car;
        struct int_list *cdr;
    };
    struct int_list endless_zeros = {0, &endless_zeros};
    eval(endless_zeros);
    struct s {
        int i;
    };
    int f (void)
    {
        struct s *p = 0, *q;
        int j = 0;
// again:
        q = p, p = &((struct s) {
            j++
        });
        if (j < 2) goto again;
        return p == q && q->i == 1;
    }
// The function f() always returns the value 1.
//  Note that if an iteration statement were used instead of an explicit goto and a label, the lifetime of the unnamed object would be the body of the loop only, and on entry next time around p would have indeterminate representation, which would result in undefined behavior.
// Forward references: type names (6.7.7), initialization (6.7.10).
// 6.5.3 Unary operators
// Syntax
//  unary-expression: postfix-expression ++ unary-expression -- unary-expression unary-operator cast-expression sizeof unary-expression sizeof ( type-name ) alignof ( type-name ) unary-operator: one of &*+-~!
// 6.5.3.1 Prefix increment and decrement operators
// Constraints
//  The operand of the prefix increment or decrement operator shall have atomic, qualified, or unquali- fied real or pointer type, and shall be a modifiable lvalue.
// Semantics
//  The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation. The expression ++E is equivalent to (E+=1), where the value 1 is of the appropriate type. See the discussions of additive operators and compound assignment for information on constraints, types, side effects, and conversions and the effects of operations on pointers.
//  The prefix -- operator is analogous to the prefix ++ operator, except that the value of the operand is decremented.
// Forward references: additive operators (6.5.6), compound assignment (6.5.16.2).
// 6.5.3.2 Address and indirection operators
// Constraints
//  The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.
//  The operand of the unary * operator shall have pointer type.
// Semantics
//  The unary & operator yields the address of its operand. If the operand has type "type", the result has type "pointer to type". If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue. Similarly, if the operand is the result of a [] operator, neither the & operator nor the unary * that is implied by the [] is evaluated and the result is as if the & operator were removed and the [] operator were changed to a + operator. Otherwise, the result is a pointer to the object or function designated by its operand.
//  The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type "pointer to type", the result has type "type". If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.115)
// Forward references: storage-class specifiers (6.7.1), structure and union specifiers (6.7.2.1).
// 6.5.3.3 Unary arithmetic operators
// Constraints
//  The operand of the unary + or − operator shall have arithmetic type; of the ~ operator, integer type; of the ! operator, scalar type.
// Semantics
//  The result of the unary + operator is the value of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.
//  The result of the unary − operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.
//  The result of the ~ operator is the bitwise complement of its (promoted) operand (that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set). The integer promotions are performed on the operand, and the result has the promoted type. If the promoted type is an unsigned type, the expression ~E is equivalent to the maximum value representable in that type minus E.
// The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E).
// 6.5.3.4 The sizeof and alignof operators
// Constraints
//  The sizeof operator shall not be applied to an expression that has function type or an incomplete type, to the parenthesized name of such a type, or to an expression that designates a bit-field member. The alignof operator shall not be applied to a function type or an incomplete type.
// Semantics
// The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.
//  The alignof operator yields the alignment requirement of its operand type. The operand is not evaluated and the result is an integer constant expression. When applied to an array type, the result is the alignment requirement of the element type.
//  When sizeof is applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1. When applied to an operand that has array type, the result is the total number of bytes in the array.116) When applied to an operand that has structure or union type, the result is the total number of bytes in such an object, including internal and trailing padding.
//  The value of the result of both operators is implementation-defined, and its type (an unsigned integer type) is size_t, defined in <stddef.h> (and other headers).
//  EXAMPLE 1 A principal use of the sizeof operator is in communication with routines such as
// 115)Thus, &*E is equivalent to E (even if E is a null pointer), and &(E1[E2]) to ((E1)+(E2)). It is always true that if E is a function designator or an lvalue that is a valid operand of the unary & operator, *&E is a function designator or an lvalue equal to E. If *P is an lvalue and T is the name of an object pointer type, *(T)P is an lvalue that has a type compatible with that to which T points. Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.
// 116)When applied to a parameter declared to have array or function type, the sizeof operator yields the size of the adjusted (pointer) type (see 6.9.1).
// storage allocators and I/O systems. A storage-allocation function might accept a size (in bytes) of an object to allocate and return a pointer to void. For example: The implementation of the alloc function presumably ensures that its return value is aligned suitably for conversion to a pointer to double.
//  EXAMPLE 2 Another use of the sizeof operator is to compute the number of elements in an array: sizeof array / sizeof array[0]
//  EXAMPLE 3 In this example, the size of a variable length array is computed and returned from a function:
    extern void *alloc(size_t);
    double *dp = alloc(sizeof *dp);
#include <stddef.h>
    size_t fsize3(int n)
    {
    }
    char b[n+3];
    return sizeof b;
// variable length array // execution time sizeof
    int main(void) {
        size_t size;
        size = fsize3(10); // fsize3 returns 13 return 0;
    }
//     Forward references: common definitions <stddef.h> (7.21), declarations (6.7), structure and union specifiers (6.7.2.1), type names (6.7.7), array declarators (6.7.6.2).
// 6.5.4 Cast operators
// Syntax
//  cast-expression:
// Constraints unary-expression ( type-name) cast-expression
//  Unless the type name specifies a void type, the type name shall specify atomic, qualified, or unqualified scalar type, and the operand shall have scalar type.
//  Conversions that involve pointers, other than where permitted by the constraints of 6.5.16.1, shall be specified by means of an explicit cast.
//  A pointer type shall not be converted to any floating type. A floating type shall not be converted to any pointer type. The type nullptr_t shall not be converted to any type other than void, bool or a pointer type. No type other than nullptr_t shall be converted to nullptr_t.
// Semantics
//  Preceding an expression by a parenthesized type name converts the value of the expression to the unqualified version of the named type. This construction is called a cast117). A cast that specifies no conversion has no effect on the type or value of an expression.
// 117)A cast does not yield an lvalue.
//  If the value of the expression is represented with greater range or precision than required by the type named by the cast (6.3.1.8), then the cast specifies a conversion even if the type of the expression is the same as the named type and removes any extra range and precision.
// Forward references: equality operators (6.5.9), function declarators (6.7.6.3), simple assignment (6.5.16.1), type names (6.7.7).
// 6.5.5 Multiplicative operators
// Syntax
//  multiplicative-expression: cast-expression multiplicative-expression * cast-expression multiplicative-expression / cast-expression multiplicative-expression % cast-expression
// Constraints
//  Each of the operands shall have arithmetic type. The operands of the % operator shall have integer type.
//  If either operand has decimal floating type, the other operand shall not have standard floating type, complex type, or imaginary type.
// Semantics
//  The usual arithmetic conversions are performed on the operands.
//  The result of the binary * operator is the product of the operands.
// The result of the / operator is the quotient from the division of the first operand by the second; the result of the % operator is the remainder. In both operations, if the value of the second operand is zero, the behavior is undefined.
// When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded.118) If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a; otherwise, the behavior of both a/b and a%b is undefined.
// 6.5.6 Additive operators
// Syntax
//  additive-expression: multiplicative-expression additive-expression + multiplicative-expression additive-expression - multiplicative-expression
// Constraints
//  For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type. (Incrementing is equivalent to adding 1.)
//  For subtraction, one of the following shall hold:
// — both operands have arithmetic type;
// — both operands are pointers to qualified or unqualified versions of compatible complete object types; or
// — the left operand is a pointer to a complete object type and the right operand has integer type.
// 118)This is often called "truncation toward zero". (Decrementing is equivalent to subtracting 1.)
//  If either operand has decimal floating type, the other operand shall not have standard floating type, complex type, or imaginary type.
// Semantics
//  If both operands have arithmetic type, the usual arithmetic conversions are performed on them.
//  The result of the binary + operator is the sum of the operands.
//  The result of the binary − operator is the difference resulting from the subtraction of the second operand from the first.
//  For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
//  When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i + n-th and i − n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If the pointer operand and the result do not point to elements of the same array object or one past the last element of the array object, the behavior is undefined. If the addition or subtraction produces an overflow, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.
//  When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. If the result is not representable in an object of that type, the behavior is undefined. In other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object, the expression (P)-(Q) has the value i − j provided the value fits in an object of type ptrdiff_t. Moreover, if the expression P points either to an element of an array object or one past the last element of an array object, and the expression Q points to the last element of the same array object, the expression ((Q)+1)-(P) has the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value zero if the expression P points one past the last element of the array object, even though the expression (Q)+1 does not point to an element of the array object.119)
//  EXAMPLE Pointer arithmetic is well defined with pointers to variable length array types.
// 119)Another way to approach pointer arithmetic is first to convert the pointer(s) to character pointer(s): In this scheme the integer expression added to or subtracted from the converted pointer is first multiplied by the size of the object originally pointed to, and the resulting pointer is converted back to the original type. For pointer subtraction, the result of the difference between the character pointers is similarly divided by the size of the object originally pointed to. When viewed in this way, an implementation need only provide one extra byte (which can overlap another object in the program) just after the end of the object to satisfy the "one past the last element" requirements.
    {
    }
    int n = 4, m = 3;
    int a[n][m];
    int (*p)[m] = a; // p == &a[0]
    p += 1;
    (*p)[2] = 99;
    n = p - a;
// p == &a[1]
// a[1][2] == 99
// n == 1
//  If array a in the above example were declared to be an array of known constant size, and pointer p were declared to be a pointer to an array of the same known constant size (pointing to a), the results would be the same.
// Forward references: array declarators (6.7.6.2), common definitions <stddef.h> (7.21).
// 6.5.7 Bitwise shift operators
// Syntax
//  shift-expression:
// Constraints
// additive-expression shift-expression << additive-expression shift-expression >> additive-expression
//  Each of the operands shall have integer type.
// Semantics
//  The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand. If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.
//  The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2, wrapped around. If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
// The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1/2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.
// 6.5.8 Relational operators
// Syntax
//  relational-expression: shift-expression relational-expression < shift-expression relational-expression > shift-expression relational-expression <= shift-expression relational-expression >= shift-expression
// Constraints
//  One of the following shall hold:
// — both operands have real type; or
// — both operands are pointers to qualified or unqualified versions of compatible object types.
//  If either operand has decimal floating type, the other operand shall not have standard floating type.
// Semantics
//  If both of the operands have arithmetic type, the usual arithmetic conversions are performed. Positive zeros compare equal to negative zeros.
//  For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
//  When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object types both point to the same object, or both point one past the last element of the same array object, they compare equal. If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal. If the expression P points to an element of an array object and the expression Q points to the last element of the same array object, the pointer expression Q+1 compares greater than P. In all other cases, the behavior is undefined.
//  Each of the operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) shall yield 1 if the specified relation is true and 0 if it is false.120). The result has type int.
// 6.5.9 Equality operators
// Syntax
//  equality-expression: relational-expression equality-expression == relational-expression equality-expression != relational-expression
// Constraints
//  One of the following shall hold:
// — both operands have arithmetic type;
// — both operands are pointers to qualified or unqualified versions of compatible types;
// — one operand is a pointer to an object type and the other is a pointer to a qualified or unqualified version of void;
// — both operands have type nullptr_t;
// — one operand has type nullptr_t and the other is a null pointer constant; or, — one operand is a pointer and the other is a null pointer constant.
//  If either operand has decimal floating type, the other operand shall not have standard floating type, complex type, or imaginary type.
// Semantics
//  The == (equal to) and != (not equal to) operators are analogous to the relational operators except for their lower precedence121) Each of the operators yields 1 if the specified relation is true and 0 if it is false. The result has type int. For any pair of operands, exactly one of the relations is true.
//  If both of the operands have arithmetic type, the usual arithmetic conversions are performed. Positive zeros compare equal to negative zeros. Values of complex types are equal if and only if both their real parts are equal and also their imaginary parts are equal. Any two values of arithmetic types from different type domains are equal if and only if the results of their conversions to the (complex) result type determined by the usual arithmetic conversions are equal. If both operands have type nullptr_t or one operand has type nullptr_t and the other is a null pointer constant, they compare equal.
//  Otherwise, at least one operand is a pointer. If one operand is a pointer and the other is a null pointer constant, the null pointer constant is converted to the type of the pointer. If one operand is a pointer to an object type and the other is a pointer to a qualified or unqualified version of void, the former is converted to the type of the latter.
// 120)The expression a<b<c is not interpreted as in ordinary mathematics. As the syntax indicates, it means (a<b)<c; in other words, "if a is less than b, compare 1 to c; otherwise, compare 0 to c".
// 121)Because of the precedences, a<b == c < d is whenever a < b and c < d have the same truth - value.
//  Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.122)
//  For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
// 6.5.10 Bitwise AND operator
// Syntax
//  AND-expression:
// Constraints
// equality-expression AND-expression & equality-expression
//  Each of the operands shall have integer type.
// Semantics
//  The usual arithmetic conversions are performed on the operands.
//  The result of the binary & operator is the bitwise AND of the operands (that is, each bit in the result is set if and only if each of the corresponding bits in the converted operands is set).
// 6.5.11 Bitwise exclusive OR operator
// Syntax
//  exclusive-OR-expression: AND-expression exclusive-OR-expression ^ AND-expression
//  Constraints
//  Each of the operands shall have integer type.
// Semantics
//  The usual arithmetic conversions are performed on the operands.
//  The result of the ^ operator is the bitwise exclusive OR of the operands (that is, each bit in the result is set if and only if exactly one of the corresponding bits in the converted operands is set).
// 6.5.12 Bitwise inclusive OR operator
// Syntax
//  inclusive-OR-expression: exclusive-OR-expression inclusive-OR-expression | exclusive-OR-expression
// Constraints
//  Each of the operands shall have integer type.
// 122)Two objects can be adjacent in memory because they are adjacent elements of a larger array or adjacent members of a structure with no padding between them, or because the implementation chose to place them so, even though they are unrelated. If prior invalid pointer operations (such as accesses outside array bounds) produced undefined behavior, subsequent comparisons also produce undefined behavior.
// The usual arithmetic conversions are performed on the operands.
//  The result of the | operator is the bitwise inclusive OR of the operands (that is, each bit in the result is set if and only if at least one of the corresponding bits in the converted operands is set).
// 6.5.13 Logical AND operator
// Syntax
//  logical-AND-expression: inclusive-OR-expression logical-AND-expression && inclusive-OR-expression
// Constraints
//  Each of the operands shall have scalar type.
// Semantics
//  The && operator shall yield 1 if both of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.
//  Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of the first and second operands. If the first operand compares equal to 0, the second operand is not evaluated.
// 6.5.14 Logical OR operator
// Syntax
//  logical-OR-expression: logical-AND-expression logical-OR-expression || logical-AND-expression
// Constraints
//  Each of the operands shall have scalar type.
// Semantics
//  The || operator shall yield 1 if either of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.
//  Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of the first and second operands. If the first operand compares unequal to 0, the second operand is not evaluated.
// 6.5.15 Conditional operator
// Syntax
//  conditional-expression: logical-OR-expression logical-OR-expression ? expression : conditional-expression
// Constraints
//  The first operand shall have scalar type.
//  One of the following shall hold for the second and third operands123):
// — both operands have arithmetic type;
// 123)If a second or third operand of type nullptr_t is used that is not a null pointer constant and the other operand is not a pointer or does not have type nullptr_t itself, a constraint is violated even if that other operand is a null pointer constant such as 0.
// — both operands have the same structure or union type;
// — both operands have void type;
// — both operands are pointers to qualified or unqualified versions of compatible types;
// — both operands have nullptr_t type;
// — one operand is a pointer and the other is a null pointer constant or has type nullptr_t; or
// — one operand is a pointer to an object type and the other is a pointer to a qualified or unqualified version of void.
//  If either of the second or third operands has decimal floating type, the other operand shall not have standard floating type, complex type, or imaginary type.
// Semantics
//  The first operand is evaluated; there is a sequence point between its evaluation and the evaluation of the second or third operand (whichever is evaluated). The second operand is evaluated only if the first compares unequal to 0; the third operand is evaluated only if the first compares equal to 0; the result is the value of the second or third operand (whichever is evaluated), converted to the type described below.124)
//  If both the second and third operands have arithmetic type, the result type that would be determined by the usual arithmetic conversions, were they applied to those two operands, is the type of the result. If both the operands have structure or union type, the result has that type. If both operands have void type, the result has void type.
//  If both the second and third operands are pointers, the result type is a pointer to a type qualified with all the type qualifiers of the types referenced by both operands; if one is a null pointer constant (other than a pointer) or has type nullptr_t and the other is a pointer, the result type is the pointer type; if both the second and third operands have nullptr_t type, the result also has that type. Furthermore, if both operands are pointers to compatible types or to differently qualified versions of compatible types, the result type is a pointer to an appropriately qualified version of the composite type; if one operand is a null pointer constant, the result has the type of the other operand; otherwise, one operand is a pointer to void or a qualified version of void, in which case the result type is a pointer to an appropriately qualified version of void.
//  EXAMPLE The common type that results when the second and third operands are pointers is determined in two independent stages. The appropriate qualifiers, for example, do not depend on whether the two pointers have compatible types.
//  Given the declarations the third column in the following table is the common type that is the result of a conditional expression in which the first two columns are the second and third operands (in either order):
    const void *c_vp;
    void *vp;
    const int *c_ip;
    volatile int *v_ip;
    int *ip;
    const char *c_cp;
//  c_vp c_ip v_ip 0 c_ip v_ip vp c_cp ip c_ip vp ip
// const void * volatile int *
// const volatile int * const void *
// const int *
// void *
//  124)A conditional expression does not yield an lvalue.
// 6.5.16 Assignment operators
// Syntax
//  assignment-expression: conditional-expression unary-expression assignment-operator assignment-expression assignment-operator: one of    =  *=  /=  %=  +=  -=  <<=  >>=  &=  ^=  |=
// Constraints
//  An assignment operator shall have a modifiable lvalue as its left operand.
// Semantics
//  An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after the assignment,125) but is not an lvalue. The type of an assignment expression is the type the left operand would have after lvalue conversion. The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced.
// 6.5.16.1 Simple assignment
// Constraints
//  One of the following shall hold126):
// — the left operand has atomic, qualified, or unqualified arithmetic type, and the right operand has arithmetic type;
// — the left operand has an atomic, qualified, or unqualified version of a structure or union type compatible with the type of the right operand;
// — the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;
// — the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;
// — the left operand has an atomic, qualified, or unqualified version of the nullptr_t type and the type of the right is nullptr_t127);
// — the left operand is an atomic, qualified, or unqualified pointer, and the type of the right operand is nullptr_t;
// — the left operand is an atomic, qualified, or unqualified bool, and the type of the right operand is nullptr_t;
//  — the left operand is an atomic, qualified, or unqualified pointer, and the right operand is a null pointer constant; or
//  — the left operand has type atomic, qualified, or unqualified bool, and the right is a pointer.
//  125)The implementation is permitted to read the object to determine the value but is not required to, even when the object has volatile-qualified type.
// 126)The asymmetric appearance of these constraints with respect to type qualifiers is due to the conversion (specified in 6.3.2.1) that changes lvalues to "the value of the expression" and thus removes any type qualifiers that were applied to the type category of the expression (for example, it removes const but not volatile from the type int volatile * const).
// 127)The assignment of an object of type nullptr_t with a value of another type, even if the value is a null pointer constant, is a constraint violation.
//  In simple assignment (=), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand. 128)
//  If the value being stored in an object is read from another object that overlaps in any way the storage of the first object, then the overlap shall exactly match and the two objects shall have qualified or unqualified versions of a compatible type; otherwise, the behavior is undefined.
//  EXAMPLE 1 In the program fragment the int value returned by the function could be truncated when stored in the char, and then converted back to int width prior to the comparison. In an implementation in which "plain" char has the same range of values as unsigned char(andcharisnarrowerthanint),theresult of the conversion cannot be negative, so the operands of the comparison can never compare equal. Therefore, for full portability, the variable c would be declared as int.
//  EXAMPLE 2 In the fragment: the value of iisconverted to the type of theassignment expressionc = i, that is, char type. The value of the expression enclosed in parentheses is then converted to the type of the outer assignment expression, that is, long int type.
//  EXAMPLE 3 Consider the fragment: The first assignment is unsafe because it would allow the following valid code to attempt to change the value of the const object c.
// 6.5.16.2 Compound assignment
// Constraints
//  For the operators += and -= only, either the left operand shall be an atomic, qualified, or unqualified pointer to a complete object type, and the right shall have integer type; or the left operand shall have atomic, qualified, or unqualified arithmetic type, and the right shall have arithmetic type.
// For the other operators, the left operand shall have atomic, qualified, or unqualified arithmetic type, and (considering the type the left operand would have after lvalue conversion) each operand shall have arithmetic type consistent with those allowed by the corresponding binary operator.
//  If either operand has decimal floating type, the other operand shall not have standard floating type, complex type, or imaginary type.
// 128)As described in 6.2.6.1, a store to an object with atomic type is done with memory_order_seq_cst semantics.
    int f(void);
    char c;
    /* ... */
    if ((c = f()) == -1)
        /* ... */
        char c;
    int i;
    long l;
    l = (c = i);
    const char **cpp;
    char *p;
    const char c = A;
    cpp = &p;
    *cpp = &c;
    *p = 0;
// constraint violation // valid
// valid
//  A compound assignment of the form E1 op= E2 is equivalent to the simple assignment expression E1 = E1 op (E2), except that the lvalue E1 is evaluated only once, and with respect to an indeterminately sequenced function call, the operation of a compound assignment is a single evaluation. If E1 has an atomic type, compound assignment is a read-modify-write operation with memory_order_seq_cst memory order semantics.
//  NOTE 1 Where a pointer to an atomic object can be formed and E1 and E2 have integer type, this is equivalent to the following code sequence where T1 is the type of E1 and T2 is the type of E2: with new being the result of the operation. If E1 or E2 has floating type, then exceptional conditions or floating-point exceptions encountered during discarded evaluations of new would also be discarded to satisfy the equivalence of E1 op= E2 and E1 = E1 op (E2). For example, if Annex F is in effect, the floating types involved have IEC 60559 binary formats, and FLT_EVAL_METHOD is 0, the equivalent code would be:
#include <fenv.h>
#pragma STDC FENV_ACCESS ON /* ... */
    fenv_t fenv;
    T1 *addr = &E1;
    T2 val = E2;
    T1 old = *addr;
    T1 new;
    feholdexcept(&fenv);
    for (;;) {
        new = old op val;
        if (atomic_compare_exchange_strong(addr, &old, new))
            break;
        feclearexcept(FE_ALL_EXCEPT);
    }
    feupdateenv(&fenv);
// If FLT_EVAL_METHOD is not 0, then T2 is expected to be a type with the range and precision to which E2 is evaluated to satisfy the equivalence.
// 6.5.17 Comma operator
    T1 *addr = &E1;
    T2 val = (E2);
    T1 old = *addr;
    T1 new;
    do {
        new = old op val;
    } while (!atomic_compare_exchange_strong(addr, &old, new));
//                                Syntax
//  expression:
// Semantics
// assignment-expression
// expression , assignment-expression
//  The left operand of a comma operator is evaluated as a void expression; there is a sequence point between its evaluation and that of the right operand. Then the right operand is evaluated; the result has its type and value.129)
//  EXAMPLE As indicated by the syntax, the comma operator (as described in this subclause) cannot appear in contexts where a comma is used to separate items in a list (such as arguments to functions or lists of initializers). On the other hand, it can be used within a parenthesized expression or within the second expression of a conditional operator in such contexts. In the function call       f(a, (t=3, t+2), c) the function has three arguments, the second of which has the value 5. Forward references: initialization (6.7.10).
// 129)A comma operator does not yield an lvalue.
    int main() {
//    PR3(st.a,st.b,st.c,d);
        printf("%s\n", n3054);
        return EXIT_SUCCESS;
    }

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

bash
$ clang p71.c -std=11 -o p71l -I. -Wall
p71.c:27:11: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
          i = ++i + 1;
          ^
p71.c:27:19: error: initializer element is not a compile-time constant
          i = ++i + 1;
              ~~~~^~~
p71.c:28:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
a[i++] = i;
^
p71.c:28:1: error: variable length array declaration not allowed at file scope
a[i++] = i;
^ ~~~
p71.c:29:18: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
                 i = i + 1;
                 ^
p71.c:29:18: error: redefinition of 'i'
p71.c:27:11: note: previous definition is here
          i = ++i + 1;
          ^
p71.c:30:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
a[i] = i;
^
p71.c:138:1: error: unknown type name 'u'
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
^
p71.c:138:2: error: expected identifier or '('
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
 ^
p71.c:138:16: error: unknown type name 'u'
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
               ^
p71.c:138:17: error: expected identifier or '('
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
                ^
p71.c:139:1: error: expected identifier or '('
if (u.n.alltypes == 1)
^
p71.c:173:11: error: use of undeclared identifier 'T'
          T *addr = &E; T old = *addr; T new;
          ^
p71.c:173:14: error: use of undeclared identifier 'addr'
          T *addr = &E; T old = *addr; T new;
             ^
p71.c:173:22: error: use of undeclared identifier 'E'
          T *addr = &E; T old = *addr; T new;
                     ^
p71.c:173:25: error: use of undeclared identifier 'T'
          T *addr = &E; T old = *addr; T new;
                        ^
p71.c:173:40: error: use of undeclared identifier 'T'
          T *addr = &E; T old = *addr; T new;
                                       ^
p71.c:175:1: error: use of undeclared identifier 'new'
new = old + 1;
^
p71.c:175:7: error: use of undeclared identifier 'old'
new = old + 1;
      ^
p71.c:176:11: warning: implicit declaration of function 'atomic_compare_exchange_strong' is invalid in C99 [-Wimplicit-function-declaration]
} while (!atomic_compare_exchange_strong(addr, &old, new));
          ^
p71.c:176:42: error: use of undeclared identifier 'addr'
} while (!atomic_compare_exchange_strong(addr, &old, new));
                                         ^
p71.c:176:49: error: use of undeclared identifier 'old'
} while (!atomic_compare_exchange_strong(addr, &old, new));
                                                ^
p71.c:176:54: error: use of undeclared identifier 'new'
} while (!atomic_compare_exchange_strong(addr, &old, new));
                                                     ^
p71.c:178:1: error: use of undeclared identifier 'SC'
SC typeof(T) ID = { IL };
^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
5 warnings and 20 errors generated.

$ clang p71.c -std=17 -o p71l -I. -Wall
p71.c:27:11: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
          i = ++i + 1;
          ^
p71.c:27:19: error: initializer element is not a compile-time constant
          i = ++i + 1;
              ~~~~^~~
p71.c:28:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
a[i++] = i;
^
p71.c:28:1: error: variable length array declaration not allowed at file scope
a[i++] = i;
^ ~~~
p71.c:29:18: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
                 i = i + 1;
                 ^
p71.c:29:18: error: redefinition of 'i'
p71.c:27:11: note: previous definition is here
          i = ++i + 1;
          ^
p71.c:30:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
a[i] = i;
^
p71.c:138:1: error: unknown type name 'u'
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
^
p71.c:138:2: error: expected identifier or '('
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
 ^
p71.c:138:16: error: unknown type name 'u'
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
               ^
p71.c:138:17: error: expected identifier or '('
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
                ^
p71.c:139:1: error: expected identifier or '('
if (u.n.alltypes == 1)
^
p71.c:173:11: error: use of undeclared identifier 'T'
          T *addr = &E; T old = *addr; T new;
          ^
p71.c:173:14: error: use of undeclared identifier 'addr'
          T *addr = &E; T old = *addr; T new;
             ^
p71.c:173:22: error: use of undeclared identifier 'E'
          T *addr = &E; T old = *addr; T new;
                     ^
p71.c:173:25: error: use of undeclared identifier 'T'
          T *addr = &E; T old = *addr; T new;
                        ^
p71.c:173:40: error: use of undeclared identifier 'T'
          T *addr = &E; T old = *addr; T new;
                                       ^
p71.c:175:1: error: use of undeclared identifier 'new'
new = old + 1;
^
p71.c:175:7: error: use of undeclared identifier 'old'
new = old + 1;
      ^
p71.c:176:11: warning: implicit declaration of function 'atomic_compare_exchange_strong' is invalid in C99 [-Wimplicit-function-declaration]
} while (!atomic_compare_exchange_strong(addr, &old, new));
          ^
p71.c:176:42: error: use of undeclared identifier 'addr'
} while (!atomic_compare_exchange_strong(addr, &old, new));
                                         ^
p71.c:176:49: error: use of undeclared identifier 'old'
} while (!atomic_compare_exchange_strong(addr, &old, new));
                                                ^
p71.c:176:54: error: use of undeclared identifier 'new'
} while (!atomic_compare_exchange_strong(addr, &old, new));
                                                     ^
p71.c:178:1: error: use of undeclared identifier 'SC'
SC typeof(T) ID = { IL };
^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
5 warnings and 20 errors generated.

$ clang p71.c -std=2x -o p71l -I. -Wall
p71.c:27:11: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
          i = ++i + 1;
          ^
p71.c:27:19: error: initializer element is not a compile-time constant
          i = ++i + 1;
              ~~~~^~~
p71.c:28:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
a[i++] = i;
^
p71.c:28:1: error: variable length array declaration not allowed at file scope
a[i++] = i;
^ ~~~
p71.c:29:18: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
                 i = i + 1;
                 ^
p71.c:29:18: error: redefinition of 'i'
p71.c:27:11: note: previous definition is here
          i = ++i + 1;
          ^
p71.c:30:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
a[i] = i;
^
p71.c:138:1: error: unknown type name 'u'
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
^
p71.c:138:2: error: expected identifier or '('
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
 ^
p71.c:138:16: error: unknown type name 'u'
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
               ^
p71.c:138:17: error: expected identifier or '('
u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
                ^
p71.c:139:1: error: expected identifier or '('
if (u.n.alltypes == 1)
^
p71.c:173:11: error: use of undeclared identifier 'T'
          T *addr = &E; T old = *addr; T new;
          ^
p71.c:173:14: error: use of undeclared identifier 'addr'
          T *addr = &E; T old = *addr; T new;
             ^
p71.c:173:22: error: use of undeclared identifier 'E'
          T *addr = &E; T old = *addr; T new;
                     ^
p71.c:173:25: error: use of undeclared identifier 'T'
          T *addr = &E; T old = *addr; T new;
                        ^
p71.c:173:40: error: use of undeclared identifier 'T'
          T *addr = &E; T old = *addr; T new;
                                       ^
p71.c:175:1: error: use of undeclared identifier 'new'
new = old + 1;
^
p71.c:175:7: error: use of undeclared identifier 'old'
new = old + 1;
      ^
p71.c:176:11: warning: implicit declaration of function 'atomic_compare_exchange_strong' is invalid in C99 [-Wimplicit-function-declaration]
} while (!atomic_compare_exchange_strong(addr, &old, new));
          ^
p71.c:176:42: error: use of undeclared identifier 'addr'
} while (!atomic_compare_exchange_strong(addr, &old, new));
                                         ^
p71.c:176:49: error: use of undeclared identifier 'old'
} while (!atomic_compare_exchange_strong(addr, &old, new));
                                                ^
p71.c:176:54: error: use of undeclared identifier 'new'
} while (!atomic_compare_exchange_strong(addr, &old, new));
                                                     ^
p71.c:178:1: error: use of undeclared identifier 'SC'
SC typeof(T) ID = { IL };
^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
5 warnings and 20 errors generated.

$ gcc p71.c -std=11 -o p71g -I. -Wall
p71.c:27:11: warning: data definition has no type or storage class
   27 |           i = ++i + 1;
      |           ^
p71.c:27:11: warning: type defaults to 'int' in declaration of 'i' [-Wimplicit-int]
p71.c:27:15: error: initializer element is not constant
   27 |           i = ++i + 1;
      |               ^~
p71.c:28:1: warning: data definition has no type or storage class
   28 | a[i++] = i;
      | ^
p71.c:28:1: warning: type defaults to 'int' in declaration of 'a' [-Wimplicit-int]
p71.c:28:1: error: variably modified 'a' at file scope
p71.c:28:10: error: invalid initializer
   28 | a[i++] = i;
      |          ^
p71.c:29:18: warning: data definition has no type or storage class
   29 |                  i = i + 1;
      |                  ^
p71.c:29:18: warning: type defaults to 'int' in declaration of 'i' [-Wimplicit-int]
p71.c:29:18: error: redefinition of 'i'
p71.c:27:11: note: previous definition of 'i' with type 'int'
   27 |           i = ++i + 1;
      |           ^
p71.c:29:22: error: initializer element is not constant
   29 |                  i = i + 1;
      |                      ^
p71.c:30:1: warning: data definition has no type or storage class
   30 | a[i] = i;
      | ^
p71.c:30:1: warning: type defaults to 'int' in declaration of 'a' [-Wimplicit-int]
p71.c:30:1: error: variably modified 'a' at file scope
p71.c:30:1: error: redefinition of 'a'
p71.c:28:1: note: previous definition of 'a' with type 'int[1]'
   28 | a[i++] = i;
      | ^
p71.c:30:8: error: invalid initializer
   30 | a[i] = i;
      |        ^
p71.c:138:2: error: expected '=', ',', ';', 'asm' or '__attribute__' before '.' token
  138 | u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
      |  ^
p71.c:138:17: error: expected '=', ',', ';', 'asm' or '__attribute__' before '.' token
  138 | u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
      |                 ^
p71.c:139:1: error: expected identifier or '(' before 'if'
  139 | if (u.n.alltypes == 1)
      | ^~
p71.c: In function 'g':
p71.c:173:11: error: unknown type name 'T'
  173 |           T *addr = &E; T old = *addr; T new;
      |           ^
p71.c:173:22: error: 'E' undeclared (first use in this function)
  173 |           T *addr = &E; T old = *addr; T new;
      |                      ^
p71.c:173:22: note: each undeclared identifier is reported only once for each function it appears in
p71.c:173:25: error: unknown type name 'T'
  173 |           T *addr = &E; T old = *addr; T new;
      |                         ^
p71.c:173:40: error: unknown type name 'T'
  173 |           T *addr = &E; T old = *addr; T new;
      |                                        ^
p71.c:176:11: warning: implicit declaration of function 'atomic_compare_exchange_strong' [-Wimplicit-function-declaration]
  176 | } while (!atomic_compare_exchange_strong(addr, &old, new));
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
p71.c:178:1: error: unknown type name 'SC'
  178 | SC typeof(T) ID = { IL };
      | ^~
p71.c:178:14: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'ID'
  178 | SC typeof(T) ID = { IL };
      |              ^~
p71.c:193:25: error: conflicting types for 'f'; have 'int(int *)'
  193 |                     int f(int*);
      |                         ^
p71.c:147:5: note: previous definition of 'f' with type 'int(struct t1 *, struct t2 *)'
  147 | int f(struct t1 *p1, struct t2 *p2) {
      |     ^
p71.c:198:30: error: conflicting types for 'f'; have 'void(void)'
  198 |                         void f(void) {
      |                              ^
p71.c:193:25: note: previous declaration of 'f' with type 'int(int *)'
  193 |                     int f(int*);
      |                         ^
p71.c:206:1: warning: value computed is not used [-Wunused-value]
  206 | (const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}
      | ^
p71.c:206:52: error: expected ';' before 'drawline'
  206 | (const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}
      |                                                    ^
      |                                                    ;
......
  211 |          drawline((struct point){.x=1, .y=1}, (struct point){.x=3, .y=4});
      |          ~~~~~~~~                                   
p71.c:212:18: warning: implicit declaration of function 'drawline' [-Wimplicit-function-declaration]
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                  ^~~~~~~~
p71.c:212:44: error: 'struct point' has no member named 'x'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                            ^
p71.c:212:46: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                              ^
p71.c:212:46: note: (near initialization for '(anonymous)')
p71.c:212:50: error: 'struct point' has no member named 'y'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                  ^
p71.c:212:52: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                    ^
p71.c:212:52: note: (near initialization for '(anonymous)')
p71.c:212:42: error: invalid use of undefined type 'struct point'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                          ^
p71.c:212:73: error: 'struct point' has no member named 'x'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                         ^
p71.c:212:75: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                           ^
p71.c:212:75: note: (near initialization for '(anonymous)')
p71.c:212:79: error: 'struct point' has no member named 'y'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                               ^
p71.c:212:81: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                                 ^
p71.c:212:81: note: (near initialization for '(anonymous)')
p71.c:212:71: error: invalid use of undefined type 'struct point'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                       ^
p71.c:214:2: error: expected expression before 'char'
  214 | (char []){"/tmp/fileXXXXXX"} (const char []){"/tmp/fileXXXXXX"}
      |  ^~~~
p71.c:213:31: error: called object is not a function or function pointer
  213 |                               "/tmp/fileXXXXXX"
      |                               ^~~~~~~~~~~~~~~~~
p71.c:214:10: error: expected ';' before '{' token
  214 | (char []){"/tmp/fileXXXXXX"} (const char []){"/tmp/fileXXXXXX"}
      |          ^
      |          ;
p71.c:215:89: error: variable 'endless_zeros' has initializer but incomplete type
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                         ^~~~~~~~
p71.c:215:115: warning: excess elements in struct initializer
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                                   ^
p71.c:215:115: note: (near initialization for 'endless_zeros')
p71.c:215:118: warning: excess elements in struct initializer
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                                      ^
p71.c:215:118: note: (near initialization for 'endless_zeros')
p71.c:215:98: error: storage size of 'endless_zeros' isn't known
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                  ^~~~~~~~~~~~~
p71.c:215:135: warning: implicit declaration of function 'eval' [-Wimplicit-function-declaration]
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                                                       ^~~~
p71.c:216:52: error: conflicting types for 'f'; have 'int(void)'
  216 |                           struct s { int i; }; int f (void)
      |                                                    ^
p71.c:198:30: note: previous definition of 'f' with type 'void(void)'
  198 |                         void f(void) {
      |                              ^
p71.c: In function 'f':
p71.c:221:1: error: label 'again' used but not defined
  221 | if (j < 2) goto again;
      | ^~
p71.c: In function 'fsize3':
p71.c:272:1: warning: no return statement in function returning non-void [-Wreturn-type]
  272 | }
      | ^
p71.c: In function 'g':
p71.c:273:8: error: 'n' undeclared (first use in this function)
  273 | char b[n+3]; return sizeof b;
      |        ^
p71.c:275:20: warning: 'main' is normally a non-static function [-Wmain]
  275 |                int main(void) {
      |                    ^~~~
p71.c: In function 'main':
p71.c:276:11: warning: variable 'size' set but not used [-Wunused-but-set-variable]
  276 |    size_t size;
      |           ^~~~
p71.c: In function 'g':
p71.c:327:7: error: conflicting types for 'p'; have 'int (*)[m]'
  327 | int (*p)[m] = a; // p == &a[0]
      |       ^
p71.c:187:6: note: previous definition of 'p' with type 'int *'
  187 | int *p = (int []){2, 4};
      |      ^
p71.c:482:14: error: non-static declaration of 'f' follows static declaration
  482 |          int f(void);
      |              ^
p71.c:216:52: note: previous definition of 'f' with type 'int(void)'
  216 |                           struct s { int i; }; int f (void)
      |                                                    ^
p71.c:487:30: error: expected expression before 'char'
  487 |                              char c; int i; long l;
      |                              ^~~~
p71.c:485:1: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
  485 | if ((c = f()) == -1)
      | ^~
p71.c:487:38: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
  487 |                              char c; int i; long l;
      |                                      ^~~
p71.c:489:54: error: conflicting types for 'p'; have 'char *'
  489 |                              const char **cpp; char *p;
      |                                                      ^
p71.c:327:7: note: previous definition of 'p' with type 'int (*)[m]'
  327 | int (*p)[m] = a; // p == &a[0]
      |       ^
p71.c:490:12: error: conflicting type qualifiers for 'c'
  490 | const char c = ’A’;
      |            ^
p71.c:483:6: note: previous declaration of 'c' with type 'char'
  483 | char c;
      |      ^
p71.c:490:16: error: stray '\342' in program
  490 | const char c = <U+2019>A<U+2019>;
      |                ^~~~~~~~
p71.c:490:18: error: stray '\342' in program
  490 | const char c = <U+2019>A<U+2019>;
      |                         ^~~~~~~~
p71.c:490:17: error: 'A' undeclared (first use in this function)
  490 | const char c = ’A’;
      |                 ^
p71.c:491:21: warning: assignment to 'const char **' from incompatible pointer type 'char **' [-Wincompatible-pointer-types]
  491 |                 cpp = &p;
      |                     ^
p71.c:499: warning: ignoring '#pragma STDC FENV_ACCESS' [-Wunknown-pragmas]
  499 | #pragma STDC FENV_ACCESS ON /* ... */
      | 
p71.c:501:1: error: unknown type name 'T1'
  501 | T1 *addr = &E1;
      | ^~
p71.c:501:5: error: redefinition of 'addr'
  501 | T1 *addr = &E1;
      |     ^~~~
p71.c:173:14: note: previous definition of 'addr' with type 'int *'
  173 |           T *addr = &E; T old = *addr; T new;
      |              ^~~~
p71.c:501:13: error: 'E1' undeclared (first use in this function); did you mean 't1'?
  501 | T1 *addr = &E1;
      |             ^~
      |             t1
p71.c:502:1: error: unknown type name 'T2'
  502 | T2 val = E2;
      | ^~
p71.c:502:10: error: 'E2' undeclared (first use in this function); did you mean 't2'?
  502 | T2 val = E2;
      |          ^~
      |          t2
p71.c:503:1: error: unknown type name 'T1'
  503 | T1 old = *addr;
      | ^~
p71.c:503:4: error: redefinition of 'old'
  503 | T1 old = *addr;
      |    ^~~
p71.c:173:27: note: previous definition of 'old' with type 'int'
  173 |           T *addr = &E; T old = *addr; T new;
      |                           ^~~
p71.c:504:1: error: unknown type name 'T1'
  504 | T1 new; feholdexcept(&fenv); for (;;) {
      | ^~
p71.c:504:4: error: redeclaration of 'new' with no linkage
  504 | T1 new; feholdexcept(&fenv); for (;;) {
      |    ^~~
p71.c:173:42: note: previous declaration of 'new' with type 'int'
  173 |           T *addr = &E; T old = *addr; T new;
      |                                          ^~~
p71.c:505:10: error: expected ';' before 'op'
  505 | new = old op val;
      |          ^~~
      |          ;
p71.c:506:1: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
  506 | if (atomic_compare_exchange_strong(addr, &old, new))
      | ^~
p71.c:507:8: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
  507 | break; feclearexcept(FE_ALL_EXCEPT);
      |        ^~~~~~~~~~~~~
p71.c:511:3: error: unknown type name 'T1'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |   ^~
p71.c:511:7: error: redefinition of 'addr'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |       ^~~~
p71.c:501:5: note: previous definition of 'addr' with type 'int *'
  501 | T1 *addr = &E1;
      |     ^~~~
p71.c:511:19: error: unknown type name 'T2'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                   ^~
p71.c:511:22: error: redefinition of 'val'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                      ^~~
p71.c:502:4: note: previous definition of 'val' with type 'int'
  502 | T2 val = E2;
      |    ^~~
p71.c:511:34: error: unknown type name 'T1'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                  ^~
p71.c:511:37: error: redefinition of 'old'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                     ^~~
p71.c:503:4: note: previous definition of 'old' with type 'int'
  503 | T1 old = *addr;
      |    ^~~
p71.c:511:50: error: unknown type name 'T1'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                                  ^~
p71.c:511:53: error: redeclaration of 'new' with no linkage
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                                     ^~~
p71.c:504:4: note: previous declaration of 'new' with type 'int'
  504 | T1 new; feholdexcept(&fenv); for (;;) {
      |    ^~~
p71.c:513:10: error: expected ';' before 'op'
  513 | new = old op val;
      |          ^~~
      |          ;
p71.c:523:5: warning: 'main' is normally a non-static function [-Wmain]
  523 | int main() {
      |     ^~~~
p71.c:523:5: error: redefinition of 'main'
p71.c:275:20: note: previous definition of 'main' with type 'int(void)'
  275 |                int main(void) {
      |                    ^~~~
p71.c:527:1: error: expected declaration or statement at end of input
  527 | }
      | ^
p71.c:511:22: warning: unused variable 'val' [-Wunused-variable]
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                      ^~~
p71.c:487:50: warning: variable 'l' set but not used [-Wunused-but-set-variable]
  487 |                              char c; int i; long l;
      |                                                  ^
p71.c:442:13: warning: unused variable 'c_cp' [-Wunused-variable]
  442 | const char *c_cp;
      |             ^~~~
p71.c:441:43: warning: unused variable 'ip' [-Wunused-variable]
  441 | const int *c_ip; volatile int *v_ip; int *ip;
      |                                           ^~
p71.c:441:32: warning: unused variable 'v_ip' [-Wunused-variable]
  441 | const int *c_ip; volatile int *v_ip; int *ip;
      |                                ^~~~
p71.c:441:12: warning: unused variable 'c_ip' [-Wunused-variable]
  441 | const int *c_ip; volatile int *v_ip; int *ip;
      |            ^~~~
p71.c:440:29: warning: unused variable 'vp' [-Wunused-variable]
  440 |     const void *c_vp; void *vp;
      |                             ^~
p71.c:440:17: warning: unused variable 'c_vp' [-Wunused-variable]
  440 |     const void *c_vp; void *vp;
      |                 ^~~~
p71.c:273:6: warning: unused variable 'b' [-Wunused-variable]
  273 | char b[n+3]; return sizeof b;
      |      ^
p71.c: At top level:
p71.c:142:53: error: storage size of 's' isn't known
  142 |         struct s { int i; const int ci; }; struct s s;
      |                                                     ^
p71.c:143:16: error: storage size of 'cs' isn't known
  143 | const struct s cs;
      |                ^~
p71.c:144:19: error: storage size of 'vs' isn't known
  144 | volatile struct s vs;
      |                   ^~
p71.c:523:5: warning: 'main' defined but not used [-Wunused-function]
  523 | int main() {
      |     ^~~~
p71.c:275:20: warning: 'main' defined but not used [-Wunused-function]
  275 |                int main(void) {
      |                    ^~~~
p71.c:216:52: warning: 'f' defined but not used [-Wunused-function]
  216 |                           struct s { int i; }; int f (void)
      |                                                    ^
p71.c:198:30: warning: 'f' defined but not used [-Wunused-function]
  198 |                         void f(void) {
      |                              ^
p71.c:194:5: warning: 'g' defined but not used [-Wunused-function]
  194 | int g(char * para[f((int[27]){ 0, })]) {
      |     ^

$ gcc p71.c -std=c17 -o p71g -I. -Wall
p71.c:27:11: warning: data definition has no type or storage class
   27 |           i = ++i + 1;
      |           ^
p71.c:27:11: warning: type defaults to 'int' in declaration of 'i' [-Wimplicit-int]
p71.c:27:15: error: initializer element is not constant
   27 |           i = ++i + 1;
      |               ^~
p71.c:28:1: warning: data definition has no type or storage class
   28 | a[i++] = i;
      | ^
p71.c:28:1: warning: type defaults to 'int' in declaration of 'a' [-Wimplicit-int]
p71.c:28:1: error: variably modified 'a' at file scope
p71.c:28:10: error: invalid initializer
   28 | a[i++] = i;
      |          ^
p71.c:29:18: warning: data definition has no type or storage class
   29 |                  i = i + 1;
      |                  ^
p71.c:29:18: warning: type defaults to 'int' in declaration of 'i' [-Wimplicit-int]
p71.c:29:18: error: redefinition of 'i'
p71.c:27:11: note: previous definition of 'i' with type 'int'
   27 |           i = ++i + 1;
      |           ^
p71.c:29:22: error: initializer element is not constant
   29 |                  i = i + 1;
      |                      ^
p71.c:30:1: warning: data definition has no type or storage class
   30 | a[i] = i;
      | ^
p71.c:30:1: warning: type defaults to 'int' in declaration of 'a' [-Wimplicit-int]
p71.c:30:1: error: variably modified 'a' at file scope
p71.c:30:1: error: redefinition of 'a'
p71.c:28:1: note: previous definition of 'a' with type 'int[1]'
   28 | a[i++] = i;
      | ^
p71.c:30:8: error: invalid initializer
   30 | a[i] = i;
      |        ^
p71.c:138:2: error: expected '=', ',', ';', 'asm' or '__attribute__' before '.' token
  138 | u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
      |  ^
p71.c:138:17: error: expected '=', ',', ';', 'asm' or '__attribute__' before '.' token
  138 | u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
      |                 ^
p71.c:139:1: error: expected identifier or '(' before 'if'
  139 | if (u.n.alltypes == 1)
      | ^~
p71.c: In function 'g':
p71.c:173:11: error: unknown type name 'T'
  173 |           T *addr = &E; T old = *addr; T new;
      |           ^
p71.c:173:22: error: 'E' undeclared (first use in this function)
  173 |           T *addr = &E; T old = *addr; T new;
      |                      ^
p71.c:173:22: note: each undeclared identifier is reported only once for each function it appears in
p71.c:173:25: error: unknown type name 'T'
  173 |           T *addr = &E; T old = *addr; T new;
      |                         ^
p71.c:173:40: error: unknown type name 'T'
  173 |           T *addr = &E; T old = *addr; T new;
      |                                        ^
p71.c:176:11: warning: implicit declaration of function 'atomic_compare_exchange_strong' [-Wimplicit-function-declaration]
  176 | } while (!atomic_compare_exchange_strong(addr, &old, new));
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
p71.c:178:1: error: unknown type name 'SC'
  178 | SC typeof(T) ID = { IL };
      | ^~
p71.c:178:14: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'ID'
  178 | SC typeof(T) ID = { IL };
      |              ^~
p71.c:193:25: error: conflicting types for 'f'; have 'int(int *)'
  193 |                     int f(int*);
      |                         ^
p71.c:147:5: note: previous definition of 'f' with type 'int(struct t1 *, struct t2 *)'
  147 | int f(struct t1 *p1, struct t2 *p2) {
      |     ^
p71.c:198:30: error: conflicting types for 'f'; have 'void(void)'
  198 |                         void f(void) {
      |                              ^
p71.c:193:25: note: previous declaration of 'f' with type 'int(int *)'
  193 |                     int f(int*);
      |                         ^
p71.c:206:1: warning: value computed is not used [-Wunused-value]
  206 | (const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}
      | ^
p71.c:206:52: error: expected ';' before 'drawline'
  206 | (const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}
      |                                                    ^
      |                                                    ;
......
  211 |          drawline((struct point){.x=1, .y=1}, (struct point){.x=3, .y=4});
      |          ~~~~~~~~                                   
p71.c:212:18: warning: implicit declaration of function 'drawline' [-Wimplicit-function-declaration]
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                  ^~~~~~~~
p71.c:212:44: error: 'struct point' has no member named 'x'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                            ^
p71.c:212:46: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                              ^
p71.c:212:46: note: (near initialization for '(anonymous)')
p71.c:212:50: error: 'struct point' has no member named 'y'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                  ^
p71.c:212:52: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                    ^
p71.c:212:52: note: (near initialization for '(anonymous)')
p71.c:212:42: error: invalid use of undefined type 'struct point'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                          ^
p71.c:212:73: error: 'struct point' has no member named 'x'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                         ^
p71.c:212:75: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                           ^
p71.c:212:75: note: (near initialization for '(anonymous)')
p71.c:212:79: error: 'struct point' has no member named 'y'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                               ^
p71.c:212:81: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                                 ^
p71.c:212:81: note: (near initialization for '(anonymous)')
p71.c:212:71: error: invalid use of undefined type 'struct point'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                       ^
p71.c:214:2: error: expected expression before 'char'
  214 | (char []){"/tmp/fileXXXXXX"} (const char []){"/tmp/fileXXXXXX"}
      |  ^~~~
p71.c:213:31: error: called object is not a function or function pointer
  213 |                               "/tmp/fileXXXXXX"
      |                               ^~~~~~~~~~~~~~~~~
p71.c:214:10: error: expected ';' before '{' token
  214 | (char []){"/tmp/fileXXXXXX"} (const char []){"/tmp/fileXXXXXX"}
      |          ^
      |          ;
p71.c:215:89: error: variable 'endless_zeros' has initializer but incomplete type
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                         ^~~~~~~~
p71.c:215:115: warning: excess elements in struct initializer
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                                   ^
p71.c:215:115: note: (near initialization for 'endless_zeros')
p71.c:215:118: warning: excess elements in struct initializer
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                                      ^
p71.c:215:118: note: (near initialization for 'endless_zeros')
p71.c:215:98: error: storage size of 'endless_zeros' isn't known
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                  ^~~~~~~~~~~~~
p71.c:215:135: warning: implicit declaration of function 'eval' [-Wimplicit-function-declaration]
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                                                       ^~~~
p71.c:216:52: error: conflicting types for 'f'; have 'int(void)'
  216 |                           struct s { int i; }; int f (void)
      |                                                    ^
p71.c:198:30: note: previous definition of 'f' with type 'void(void)'
  198 |                         void f(void) {
      |                              ^
p71.c: In function 'f':
p71.c:221:1: error: label 'again' used but not defined
  221 | if (j < 2) goto again;
      | ^~
p71.c: In function 'fsize3':
p71.c:272:1: warning: no return statement in function returning non-void [-Wreturn-type]
  272 | }
      | ^
p71.c: In function 'g':
p71.c:273:8: error: 'n' undeclared (first use in this function)
  273 | char b[n+3]; return sizeof b;
      |        ^
p71.c:275:20: warning: 'main' is normally a non-static function [-Wmain]
  275 |                int main(void) {
      |                    ^~~~
p71.c: In function 'main':
p71.c:276:11: warning: variable 'size' set but not used [-Wunused-but-set-variable]
  276 |    size_t size;
      |           ^~~~
p71.c: In function 'g':
p71.c:327:7: error: conflicting types for 'p'; have 'int (*)[m]'
  327 | int (*p)[m] = a; // p == &a[0]
      |       ^
p71.c:187:6: note: previous definition of 'p' with type 'int *'
  187 | int *p = (int []){2, 4};
      |      ^
p71.c:482:14: error: non-static declaration of 'f' follows static declaration
  482 |          int f(void);
      |              ^
p71.c:216:52: note: previous definition of 'f' with type 'int(void)'
  216 |                           struct s { int i; }; int f (void)
      |                                                    ^
p71.c:487:30: error: expected expression before 'char'
  487 |                              char c; int i; long l;
      |                              ^~~~
p71.c:485:1: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
  485 | if ((c = f()) == -1)
      | ^~
p71.c:487:38: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
  487 |                              char c; int i; long l;
      |                                      ^~~
p71.c:489:54: error: conflicting types for 'p'; have 'char *'
  489 |                              const char **cpp; char *p;
      |                                                      ^
p71.c:327:7: note: previous definition of 'p' with type 'int (*)[m]'
  327 | int (*p)[m] = a; // p == &a[0]
      |       ^
p71.c:490:12: error: conflicting type qualifiers for 'c'
  490 | const char c = ’A’;
      |            ^
p71.c:483:6: note: previous declaration of 'c' with type 'char'
  483 | char c;
      |      ^
p71.c:490:16: error: stray '\342' in program
  490 | const char c = <U+2019>A<U+2019>;
      |                ^~~~~~~~
p71.c:490:18: error: stray '\342' in program
  490 | const char c = <U+2019>A<U+2019>;
      |                         ^~~~~~~~
p71.c:490:17: error: 'A' undeclared (first use in this function)
  490 | const char c = ’A’;
      |                 ^
p71.c:491:21: warning: assignment to 'const char **' from incompatible pointer type 'char **' [-Wincompatible-pointer-types]
  491 |                 cpp = &p;
      |                     ^
p71.c:499: warning: ignoring '#pragma STDC FENV_ACCESS' [-Wunknown-pragmas]
  499 | #pragma STDC FENV_ACCESS ON /* ... */
      | 
p71.c:501:1: error: unknown type name 'T1'
  501 | T1 *addr = &E1;
      | ^~
p71.c:501:5: error: redefinition of 'addr'
  501 | T1 *addr = &E1;
      |     ^~~~
p71.c:173:14: note: previous definition of 'addr' with type 'int *'
  173 |           T *addr = &E; T old = *addr; T new;
      |              ^~~~
p71.c:501:13: error: 'E1' undeclared (first use in this function); did you mean 't1'?
  501 | T1 *addr = &E1;
      |             ^~
      |             t1
p71.c:502:1: error: unknown type name 'T2'
  502 | T2 val = E2;
      | ^~
p71.c:502:10: error: 'E2' undeclared (first use in this function); did you mean 't2'?
  502 | T2 val = E2;
      |          ^~
      |          t2
p71.c:503:1: error: unknown type name 'T1'
  503 | T1 old = *addr;
      | ^~
p71.c:503:4: error: redefinition of 'old'
  503 | T1 old = *addr;
      |    ^~~
p71.c:173:27: note: previous definition of 'old' with type 'int'
  173 |           T *addr = &E; T old = *addr; T new;
      |                           ^~~
p71.c:504:1: error: unknown type name 'T1'
  504 | T1 new; feholdexcept(&fenv); for (;;) {
      | ^~
p71.c:504:4: error: redeclaration of 'new' with no linkage
  504 | T1 new; feholdexcept(&fenv); for (;;) {
      |    ^~~
p71.c:173:42: note: previous declaration of 'new' with type 'int'
  173 |           T *addr = &E; T old = *addr; T new;
      |                                          ^~~
p71.c:505:10: error: expected ';' before 'op'
  505 | new = old op val;
      |          ^~~
      |          ;
p71.c:506:1: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
  506 | if (atomic_compare_exchange_strong(addr, &old, new))
      | ^~
p71.c:507:8: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
  507 | break; feclearexcept(FE_ALL_EXCEPT);
      |        ^~~~~~~~~~~~~
p71.c:511:3: error: unknown type name 'T1'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |   ^~
p71.c:511:7: error: redefinition of 'addr'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |       ^~~~
p71.c:501:5: note: previous definition of 'addr' with type 'int *'
  501 | T1 *addr = &E1;
      |     ^~~~
p71.c:511:19: error: unknown type name 'T2'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                   ^~
p71.c:511:22: error: redefinition of 'val'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                      ^~~
p71.c:502:4: note: previous definition of 'val' with type 'int'
  502 | T2 val = E2;
      |    ^~~
p71.c:511:34: error: unknown type name 'T1'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                  ^~
p71.c:511:37: error: redefinition of 'old'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                     ^~~
p71.c:503:4: note: previous definition of 'old' with type 'int'
  503 | T1 old = *addr;
      |    ^~~
p71.c:511:50: error: unknown type name 'T1'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                                  ^~
p71.c:511:53: error: redeclaration of 'new' with no linkage
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                                     ^~~
p71.c:504:4: note: previous declaration of 'new' with type 'int'
  504 | T1 new; feholdexcept(&fenv); for (;;) {
      |    ^~~
p71.c:513:10: error: expected ';' before 'op'
  513 | new = old op val;
      |          ^~~
      |          ;
p71.c:523:5: warning: 'main' is normally a non-static function [-Wmain]
  523 | int main() {
      |     ^~~~
p71.c:523:5: error: redefinition of 'main'
p71.c:275:20: note: previous definition of 'main' with type 'int(void)'
  275 |                int main(void) {
      |                    ^~~~
p71.c:527:1: error: expected declaration or statement at end of input
  527 | }
      | ^
p71.c:511:22: warning: unused variable 'val' [-Wunused-variable]
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                      ^~~
p71.c:487:50: warning: variable 'l' set but not used [-Wunused-but-set-variable]
  487 |                              char c; int i; long l;
      |                                                  ^
p71.c:442:13: warning: unused variable 'c_cp' [-Wunused-variable]
  442 | const char *c_cp;
      |             ^~~~
p71.c:441:43: warning: unused variable 'ip' [-Wunused-variable]
  441 | const int *c_ip; volatile int *v_ip; int *ip;
      |                                           ^~
p71.c:441:32: warning: unused variable 'v_ip' [-Wunused-variable]
  441 | const int *c_ip; volatile int *v_ip; int *ip;
      |                                ^~~~
p71.c:441:12: warning: unused variable 'c_ip' [-Wunused-variable]
  441 | const int *c_ip; volatile int *v_ip; int *ip;
      |            ^~~~
p71.c:440:29: warning: unused variable 'vp' [-Wunused-variable]
  440 |     const void *c_vp; void *vp;
      |                             ^~
p71.c:440:17: warning: unused variable 'c_vp' [-Wunused-variable]
  440 |     const void *c_vp; void *vp;
      |                 ^~~~
p71.c:273:6: warning: unused variable 'b' [-Wunused-variable]
  273 | char b[n+3]; return sizeof b;
      |      ^
p71.c: At top level:
p71.c:142:53: error: storage size of 's' isn't known
  142 |         struct s { int i; const int ci; }; struct s s;
      |                                                     ^
p71.c:143:16: error: storage size of 'cs' isn't known
  143 | const struct s cs;
      |                ^~
p71.c:144:19: error: storage size of 'vs' isn't known
  144 | volatile struct s vs;
      |                   ^~
p71.c:523:5: warning: 'main' defined but not used [-Wunused-function]
  523 | int main() {
      |     ^~~~
p71.c:275:20: warning: 'main' defined but not used [-Wunused-function]
  275 |                int main(void) {
      |                    ^~~~
p71.c:216:52: warning: 'f' defined but not used [-Wunused-function]
  216 |                           struct s { int i; }; int f (void)
      |                                                    ^
p71.c:198:30: warning: 'f' defined but not used [-Wunused-function]
  198 |                         void f(void) {
      |                              ^
p71.c:194:5: warning: 'g' defined but not used [-Wunused-function]
  194 | int g(char * para[f((int[27]){ 0, })]) {
      |     ^

$ gcc p71.c -std=c2x -o p71g -I. -Wall
p71.c:27:11: warning: data definition has no type or storage class
   27 |           i = ++i + 1;
      |           ^
p71.c:27:11: warning: type defaults to 'int' in declaration of 'i' [-Wimplicit-int]
p71.c:27:15: error: initializer element is not constant
   27 |           i = ++i + 1;
      |               ^~
p71.c:28:1: warning: data definition has no type or storage class
   28 | a[i++] = i;
      | ^
p71.c:28:1: warning: type defaults to 'int' in declaration of 'a' [-Wimplicit-int]
p71.c:28:1: error: variably modified 'a' at file scope
p71.c:28:10: error: invalid initializer
   28 | a[i++] = i;
      |          ^
p71.c:29:18: warning: data definition has no type or storage class
   29 |                  i = i + 1;
      |                  ^
p71.c:29:18: warning: type defaults to 'int' in declaration of 'i' [-Wimplicit-int]
p71.c:29:18: error: redefinition of 'i'
p71.c:27:11: note: previous definition of 'i' with type 'int'
   27 |           i = ++i + 1;
      |           ^
p71.c:29:22: error: initializer element is not constant
   29 |                  i = i + 1;
      |                      ^
p71.c:30:1: warning: data definition has no type or storage class
   30 | a[i] = i;
      | ^
p71.c:30:1: warning: type defaults to 'int' in declaration of 'a' [-Wimplicit-int]
p71.c:30:1: error: variably modified 'a' at file scope
p71.c:30:1: error: redefinition of 'a'
p71.c:28:1: note: previous definition of 'a' with type 'int[1]'
   28 | a[i++] = i;
      | ^
p71.c:30:8: error: invalid initializer
   30 | a[i] = i;
      |        ^
p71.c:138:2: error: expected '=', ',', ';', 'asm' or '__attribute__' before '.' token
  138 | u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
      |  ^
p71.c:138:17: error: expected '=', ',', ';', 'asm' or '__attribute__' before '.' token
  138 | u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */
      |                 ^
p71.c:139:1: error: expected identifier or '(' before 'if'
  139 | if (u.n.alltypes == 1)
      | ^~
p71.c: In function 'g':
p71.c:173:11: error: unknown type name 'T'
  173 |           T *addr = &E; T old = *addr; T new;
      |           ^
p71.c:173:22: error: 'E' undeclared (first use in this function)
  173 |           T *addr = &E; T old = *addr; T new;
      |                      ^
p71.c:173:22: note: each undeclared identifier is reported only once for each function it appears in
p71.c:173:25: error: unknown type name 'T'
  173 |           T *addr = &E; T old = *addr; T new;
      |                         ^
p71.c:173:40: error: unknown type name 'T'
  173 |           T *addr = &E; T old = *addr; T new;
      |                                        ^
p71.c:176:11: warning: implicit declaration of function 'atomic_compare_exchange_strong' [-Wimplicit-function-declaration]
  176 | } while (!atomic_compare_exchange_strong(addr, &old, new));
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
p71.c:178:1: error: unknown type name 'SC'
  178 | SC typeof(T) ID = { IL };
      | ^~
p71.c:178:14: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'ID'
  178 | SC typeof(T) ID = { IL };
      |              ^~
p71.c:193:25: error: conflicting types for 'f'; have 'int(int *)'
  193 |                     int f(int*);
      |                         ^
p71.c:147:5: note: previous definition of 'f' with type 'int(struct t1 *, struct t2 *)'
  147 | int f(struct t1 *p1, struct t2 *p2) {
      |     ^
p71.c:198:30: error: conflicting types for 'f'; have 'void(void)'
  198 |                         void f(void) {
      |                              ^
p71.c:193:25: note: previous declaration of 'f' with type 'int(int *)'
  193 |                     int f(int*);
      |                         ^
p71.c:206:1: warning: value computed is not used [-Wunused-value]
  206 | (const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}
      | ^
p71.c:206:52: error: expected ';' before 'drawline'
  206 | (const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}
      |                                                    ^
      |                                                    ;
......
  211 |          drawline((struct point){.x=1, .y=1}, (struct point){.x=3, .y=4});
      |          ~~~~~~~~                                   
p71.c:212:18: warning: implicit declaration of function 'drawline' [-Wimplicit-function-declaration]
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                  ^~~~~~~~
p71.c:212:44: error: 'struct point' has no member named 'x'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                            ^
p71.c:212:46: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                              ^
p71.c:212:46: note: (near initialization for '(anonymous)')
p71.c:212:50: error: 'struct point' has no member named 'y'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                  ^
p71.c:212:52: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                    ^
p71.c:212:52: note: (near initialization for '(anonymous)')
p71.c:212:42: error: invalid use of undefined type 'struct point'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                          ^
p71.c:212:73: error: 'struct point' has no member named 'x'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                         ^
p71.c:212:75: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                           ^
p71.c:212:75: note: (near initialization for '(anonymous)')
p71.c:212:79: error: 'struct point' has no member named 'y'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                               ^
p71.c:212:81: warning: excess elements in struct initializer
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                                 ^
p71.c:212:81: note: (near initialization for '(anonymous)')
p71.c:212:71: error: invalid use of undefined type 'struct point'
  212 |                  drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});
      |                                                                       ^
p71.c:214:2: error: expected expression before 'char'
  214 | (char []){"/tmp/fileXXXXXX"} (const char []){"/tmp/fileXXXXXX"}
      |  ^~~~
p71.c:213:31: error: called object is not a function or function pointer
  213 |                               "/tmp/fileXXXXXX"
      |                               ^~~~~~~~~~~~~~~~~
p71.c:214:10: error: expected ';' before '{' token
  214 | (char []){"/tmp/fileXXXXXX"} (const char []){"/tmp/fileXXXXXX"}
      |          ^
      |          ;
p71.c:215:89: error: variable 'endless_zeros' has initializer but incomplete type
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                         ^~~~~~~~
p71.c:215:115: warning: excess elements in struct initializer
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                                   ^
p71.c:215:115: note: (near initialization for 'endless_zeros')
p71.c:215:118: warning: excess elements in struct initializer
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                                      ^
p71.c:215:118: note: (near initialization for 'endless_zeros')
p71.c:215:98: error: storage size of 'endless_zeros' isn't known
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                  ^~~~~~~~~~~~~
p71.c:215:135: warning: implicit declaration of function 'eval' [-Wimplicit-function-declaration]
  215 |                              struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros);
      |                                                                                                                                       ^~~~
p71.c:216:52: error: conflicting types for 'f'; have 'int(void)'
  216 |                           struct s { int i; }; int f (void)
      |                                                    ^
p71.c:198:30: note: previous definition of 'f' with type 'void(void)'
  198 |                         void f(void) {
      |                              ^
p71.c: In function 'f':
p71.c:221:1: error: label 'again' used but not defined
  221 | if (j < 2) goto again;
      | ^~
p71.c: In function 'fsize3':
p71.c:272:1: warning: no return statement in function returning non-void [-Wreturn-type]
  272 | }
      | ^
p71.c: In function 'g':
p71.c:273:8: error: 'n' undeclared (first use in this function)
  273 | char b[n+3]; return sizeof b;
      |        ^
p71.c:275:20: warning: 'main' is normally a non-static function [-Wmain]
  275 |                int main(void) {
      |                    ^~~~
p71.c: In function 'main':
p71.c:276:11: warning: variable 'size' set but not used [-Wunused-but-set-variable]
  276 |    size_t size;
      |           ^~~~
p71.c: In function 'g':
p71.c:327:7: error: conflicting types for 'p'; have 'int (*)[m]'
  327 | int (*p)[m] = a; // p == &a[0]
      |       ^
p71.c:187:6: note: previous definition of 'p' with type 'int *'
  187 | int *p = (int []){2, 4};
      |      ^
p71.c:482:14: error: non-static declaration of 'f' follows static declaration
  482 |          int f(void);
      |              ^
p71.c:216:52: note: previous definition of 'f' with type 'int(void)'
  216 |                           struct s { int i; }; int f (void)
      |                                                    ^
p71.c:487:30: error: expected expression before 'char'
  487 |                              char c; int i; long l;
      |                              ^~~~
p71.c:485:1: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
  485 | if ((c = f()) == -1)
      | ^~
p71.c:487:38: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
  487 |                              char c; int i; long l;
      |                                      ^~~
p71.c:489:54: error: conflicting types for 'p'; have 'char *'
  489 |                              const char **cpp; char *p;
      |                                                      ^
p71.c:327:7: note: previous definition of 'p' with type 'int (*)[m]'
  327 | int (*p)[m] = a; // p == &a[0]
      |       ^
p71.c:490:12: error: conflicting type qualifiers for 'c'
  490 | const char c = ’A’;
      |            ^
p71.c:483:6: note: previous declaration of 'c' with type 'char'
  483 | char c;
      |      ^
p71.c:490:16: error: stray '\342' in program
  490 | const char c = <U+2019>A<U+2019>;
      |                ^~~~~~~~
p71.c:490:18: error: stray '\342' in program
  490 | const char c = <U+2019>A<U+2019>;
      |                         ^~~~~~~~
p71.c:490:17: error: 'A' undeclared (first use in this function)
  490 | const char c = ’A’;
      |                 ^
p71.c:491:21: warning: assignment to 'const char **' from incompatible pointer type 'char **' [-Wincompatible-pointer-types]
  491 |                 cpp = &p;
      |                     ^
p71.c:499: warning: ignoring '#pragma STDC FENV_ACCESS' [-Wunknown-pragmas]
  499 | #pragma STDC FENV_ACCESS ON /* ... */
      | 
p71.c:501:1: error: unknown type name 'T1'
  501 | T1 *addr = &E1;
      | ^~
p71.c:501:5: error: redefinition of 'addr'
  501 | T1 *addr = &E1;
      |     ^~~~
p71.c:173:14: note: previous definition of 'addr' with type 'int *'
  173 |           T *addr = &E; T old = *addr; T new;
      |              ^~~~
p71.c:501:13: error: 'E1' undeclared (first use in this function); did you mean 't1'?
  501 | T1 *addr = &E1;
      |             ^~
      |             t1
p71.c:502:1: error: unknown type name 'T2'
  502 | T2 val = E2;
      | ^~
p71.c:502:10: error: 'E2' undeclared (first use in this function); did you mean 't2'?
  502 | T2 val = E2;
      |          ^~
      |          t2
p71.c:503:1: error: unknown type name 'T1'
  503 | T1 old = *addr;
      | ^~
p71.c:503:4: error: redefinition of 'old'
  503 | T1 old = *addr;
      |    ^~~
p71.c:173:27: note: previous definition of 'old' with type 'int'
  173 |           T *addr = &E; T old = *addr; T new;
      |                           ^~~
p71.c:504:1: error: unknown type name 'T1'
  504 | T1 new; feholdexcept(&fenv); for (;;) {
      | ^~
p71.c:504:4: error: redeclaration of 'new' with no linkage
  504 | T1 new; feholdexcept(&fenv); for (;;) {
      |    ^~~
p71.c:173:42: note: previous declaration of 'new' with type 'int'
  173 |           T *addr = &E; T old = *addr; T new;
      |                                          ^~~
p71.c:505:10: error: expected ';' before 'op'
  505 | new = old op val;
      |          ^~~
      |          ;
p71.c:506:1: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
  506 | if (atomic_compare_exchange_strong(addr, &old, new))
      | ^~
p71.c:507:8: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
  507 | break; feclearexcept(FE_ALL_EXCEPT);
      |        ^~~~~~~~~~~~~
p71.c:511:3: error: unknown type name 'T1'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |   ^~
p71.c:511:7: error: redefinition of 'addr'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |       ^~~~
p71.c:501:5: note: previous definition of 'addr' with type 'int *'
  501 | T1 *addr = &E1;
      |     ^~~~
p71.c:511:19: error: unknown type name 'T2'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                   ^~
p71.c:511:22: error: redefinition of 'val'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                      ^~~
p71.c:502:4: note: previous definition of 'val' with type 'int'
  502 | T2 val = E2;
      |    ^~~
p71.c:511:34: error: unknown type name 'T1'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                  ^~
p71.c:511:37: error: redefinition of 'old'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                     ^~~
p71.c:503:4: note: previous definition of 'old' with type 'int'
  503 | T1 old = *addr;
      |    ^~~
p71.c:511:50: error: unknown type name 'T1'
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                                  ^~
p71.c:511:53: error: redeclaration of 'new' with no linkage
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                                                     ^~~
p71.c:504:4: note: previous declaration of 'new' with type 'int'
  504 | T1 new; feholdexcept(&fenv); for (;;) {
      |    ^~~
p71.c:513:10: error: expected ';' before 'op'
  513 | new = old op val;
      |          ^~~
      |          ;
p71.c:523:5: warning: 'main' is normally a non-static function [-Wmain]
  523 | int main() {
      |     ^~~~
p71.c:523:5: error: redefinition of 'main'
p71.c:275:20: note: previous definition of 'main' with type 'int(void)'
  275 |                int main(void) {
      |                    ^~~~
p71.c:527:1: error: expected declaration or statement at end of input
  527 | }
      | ^
p71.c:511:22: warning: unused variable 'val' [-Wunused-variable]
  511 |   T1 *addr = &E1; T2 val = (E2); T1 old = *addr; T1 new;
      |                      ^~~
p71.c:487:50: warning: variable 'l' set but not used [-Wunused-but-set-variable]
  487 |                              char c; int i; long l;
      |                                                  ^
p71.c:442:13: warning: unused variable 'c_cp' [-Wunused-variable]
  442 | const char *c_cp;
      |             ^~~~
p71.c:441:43: warning: unused variable 'ip' [-Wunused-variable]
  441 | const int *c_ip; volatile int *v_ip; int *ip;
      |                                           ^~
p71.c:441:32: warning: unused variable 'v_ip' [-Wunused-variable]
  441 | const int *c_ip; volatile int *v_ip; int *ip;
      |                                ^~~~
p71.c:441:12: warning: unused variable 'c_ip' [-Wunused-variable]
  441 | const int *c_ip; volatile int *v_ip; int *ip;
      |            ^~~~
p71.c:440:29: warning: unused variable 'vp' [-Wunused-variable]
  440 |     const void *c_vp; void *vp;
      |                             ^~
p71.c:440:17: warning: unused variable 'c_vp' [-Wunused-variable]
  440 |     const void *c_vp; void *vp;
      |                 ^~~~
p71.c:273:6: warning: unused variable 'b' [-Wunused-variable]
  273 | char b[n+3]; return sizeof b;
      |      ^
p71.c: At top level:
p71.c:142:53: error: storage size of 's' isn't known
  142 |         struct s { int i; const int ci; }; struct s s;
      |                                                     ^
p71.c:143:16: error: storage size of 'cs' isn't known
  143 | const struct s cs;
      |                ^~
p71.c:144:19: error: storage size of 'vs' isn't known
  144 | volatile struct s vs;
      |                   ^~
p71.c:523:5: warning: 'main' defined but not used [-Wunused-function]
  523 | int main() {
      |     ^~~~
p71.c:275:20: warning: 'main' defined but not used [-Wunused-function]
  275 |                int main(void) {
      |                    ^~~~
p71.c:216:52: warning: 'f' defined but not used [-Wunused-function]
  216 |                           struct s { int i; }; int f (void)
      |                                                    ^
p71.c:198:30: warning: 'f' defined but not used [-Wunused-function]
  198 |                         void f(void) {
      |                              ^
p71.c:194:5: warning: 'g' defined but not used [-Wunused-function]
  194 | int g(char * para[f((int[27]){ 0, })]) {
      |     ^

検討事項(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++)に対する誤解、曲解、無理解、爽快。

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
ver. 0.02 N3054 URLリンク切れ 変更, C言語教育はCコンパイラの写経で URL追記 20221029

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

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

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?