非常教程

C参考手册

C 语法

Struct and union initialization

在初始化struct或union类型的对象时,初始值设定项必须是成员的非空的,括号括起来的以逗号分隔的初始值设定项列表:

= {表达式,...}

(直到C99)

= {指定者(可选)表达式,...}

(自C99以来)

其中指示符是.表单[索引中的表单成员和数组指示符的各个成员标识符的序列(空格分隔或相邻)]

所有未明确初始化的成员都会以与具有静态存储持续时间的对象相同的方式隐式初始化。

说明

初始化联合时,初始化程序列表必须只有一个成员,它将初始化联合的第一个成员,除非使用了指定的初始化程序(自C99以来)。

union { int x; char c[4]; }
  u = {1},           // makes u.x active with value 1
 u2 = { .c={'\1'} }; // makes u2.c active with value {'\1','\0','\0','\0'}

当初始化一个结构时,列表中的第一个初始化器初始化第一个声明的成员(除非指定了指定符)(自C99开始),并且没有指定符的所有后续初始化器(自C99开始)初始化在先前由表达。

struct point {double x,y,z;} p = {1.2, 1.3}; // p.x=1.2, p.y=1.3, p.z=0.0
div_t answer = {.quot = 2, .rem = -1 };      // order of elements in div_t may vary

指示符使下列初始化程序初始化由指定符描述的结构成员。然后按照声明的顺序继续初始化,从在指定符描述的声明之后声明的下一个元素开始。struct {int sec,min,hour,day,mon,year;} z = {.day = 31,12,2014,.sec = 30,15,17}; //将z初始化为{30,15,17,31,12,2014}

(自C99以来)

提供比成员更多的初始化器是错误的。

嵌套初始化

如果结构体或联合体的成员是数组,结构体或联合体,则大括号括起来的初始化程序中相应的初始化程序是对这些成员有效的任何初始化程序,除了它们的大括号可以省略如下:

如果嵌套的初始化程序以一个左大括号开始,则整个嵌套初始化程序直到其大括号初始化相应的成员对象。每个左开口大括号建立一个新的当前对象。当前对象的成员以自然顺序进行初始化,除非使用了指示符(自C99起):数组元素以下标顺序,声明顺序的struct成员,仅为任何联合的第一个声明成员。当前对象内的子对象没有被右括号显式初始化,它们被隐式初始化。

struct example {
    struct addr_t {
       uint32_t port;
    } addr;
    union {
       uint8_t a8[4];
       uint16_t a16[2];
    } in_u;
};
struct example ex = { // start of initializer list for struct example
                     { // start of initializer list for ex.addr
                        80 // initialized struct's only member
                     }, // end of initializer list for ex.addr
                     { // start of initializer-list for ex.in_u
                        {127,0,0,1} // initializes first element of the union
                     } };

如果嵌套的初始化程序不是以大括号开始,则只有足够的初始化程序才会考虑成员数组的元素或成员struct或union; 任何剩余的初始化器都将被初始化为下一个结构成员:

struct example ex = {80, 127, 0, 0, 1}; // 80 initializes ex.addr.port
                                        // 127 initializes ex.in_u.a8[0]
                                        // 0 initializes ex.in_u.a8[1]
                                        // 0 initializes ex.in_u.a8[2]
                                        // 1 initializes ex.in_u.a8[3]

When designators are nested, the designators for the members follow the designators for the enclosing structs/unions/arrays. Within any nested bracketed initializer list, the outermost designator refers to the current object and selects the subobject to be initialized within the current object only. struct example ex2 = { // current object is ex2, designators are for members of example .in_u.a80=127, 0, 0, 1, .addr=80}; struct example ex3 = {80, .in_u={ // changes current object to the union ex.in_u 127, .a82=1 // this designator refers to the member of in_u } }; If any subobject is explicitly initialized twice (which may happen when designators are used), the initializer that appears later in the list is the one used (the earlier initializer may not be evaluated): struct {int n;} s = {printf("a\n"), // this may be printed or skipped .n=printf("b\n")}; // always printed Although any non-initialized subobjects are initialized implicitly, implicit initialization of a subobject never overrides explicit initialization of the same subobject if it appeared earlier in the initializer list: #include <stdio.h> typedef struct { int k; int l; int a2; } T; typedef struct { int i; T t; } S; T x = {.l = 43, .k = 42, .a1 = 19, .a0 = 18 }; // x initialized to {42, 43, {18, 19} } int main(void) { S l = { 1, // initializes l.i to 1 .t = x, // initializes l.t to {42, 43, {18, 19} } .t.l = 41, // changes l.t to {42, 41, {18, 19} } .t.a1 = 17 // changes l.t to {42, 41, {18, 17} } }; printf("l.t.k is %d\n", l.t.k); // .t = x sets l.t.k to 42 explicitly // .t.l = 42 would zero out l.t.k implicitly } Output: l.t.k is 42 However, when an initializer begins with a left open brace, its current object is fully re-initialized and any prior explicit initializers for any of its subobjects are ignored: struct fred { char s4; int n; }; struct fred x = { { { "abc" }, 1 }, // inits x0 to { {'a','b','c','\0'}, 1 } 0.s0 = 'q' // changes x0 to { {'q','b','c','\0'}, 1 } }; struct fred y = { { { "abc" }, 1 }, // inits y0 to { {'a','b','c','\0'}, 1 } 0 = { // current object is now the entire y0 object .s0 = 'q' } // replaces y0 with { {'q','\0','\0','\0'}, 0 } };

(自C99以来)

注释

任何初始化器中子表达式的评估顺序都是非确定的:

int n = 1;
struct {int x,y;} p = {n++, n++}; // unspecified, but well-defined behavior:
                                  // n is incremented twice in arbitrary order
                                  // p equal {1,2} and {2,1} are both valid

在C中,初始化器的支撑列表不能为空(请注意,C ++允许空列表,并且还要注意C中的结构不能为空):

struct {int n;} s = {0}; // OK
struct {int n;} s = {}; // Error: initializer-list cannot be empty
struct {} s = {}; // Error: struct cannot be empty, initializer-list cannot be empty

与所有其他初始化一样,初始化器列表中的每个表达式在初始化静态或线程本地存储持续时间数组时都必须是常量表达式:

static struct {char* p} s = {malloc(1)}; // error

初始化程序列表可能会有一个尾随逗号,这会被忽略。

struct {double x,y;} p = {1.0,
                          2.0, // trailing comma OK
                          };

#include <stdio.h>
#include <time.h>
 
int main(void)
{
    char buff[70];
    // designated initalizers simplify the use of structs whose
    // order of members is unspecified
    struct tm my_time = { .tm_year=112, .tm_mon=9, .tm_mday=9,
                          .tm_hour=8, .tm_min=10, .tm_sec=20 };
    strftime(buff, sizeof buff, "%A %c", &my_time);
    puts(buff);
}

可能的输出:

Sunday Sun Oct  9 08:10:20 2012

参考

  • C11标准(ISO / IEC 9899:2011):
    • 6.7.9 / 12-38初始化(p:140-144)
  • C99标准(ISO / IEC 9899:1999):
    • 6.7.8 / 12-38初始化(p:126-130)
  • C89 / C90标准(ISO / IEC 9899:1990):
    • 3.5.7 / 9-初始化

C 语法相关

1.#define directive
2.#elif directive
3.#else directive
4.#endif directive
5.#error directive
6.#if directive
7.#ifdef directive
8.#ifndef directive
9.#include directive
10.#line directive
11.#pragma directive
12.alignas
13.Alternative operators and tokens
14.Analyzability
15.Arithmetic operators
16.Arithmetic types
17.Array declaration
18.Array initialization
19.ASCII Chart
20.Assignment operators
21. types
22.Basic concepts
23.Bit fields
24.break statement
25.C language
26.C Operator Precedence
27.cast operator
28.character constant
29.Comments
30.Comparison operators
31.compound literals
32.Conditional inclusion
33.Conformance
34.const type qualifier
35.Constant expressions
36.continue statement
37.Declarations
38.do-while loop
39.Enumerations
40.Escape sequences
41.Expressions
42.External and tentative definitions
43.File scope
44.floating constant
45.for loop
46.Function declarations
47.Function definitions
48.Functions
49.Generic selection
50.goto statement
51.Identifier
52.if statement
53.Implicit conversions
54.Increment/decrement operators
55.Initialization
56.inline function specifier
57.integer constant
58.Lifetime
59.Logical operators
60.Lookup and name spaces
61.Main function
62.Member access operators
63.Memory model
64.Objects and alignment
65.Order of evaluation
66.Other operators
67.Phases of translation
68.Pointer declaration
69.Preprocessor
70.restrict type qualifier
71.return statement
72.Scalar initialization
73.Scope
74.sizeof operator
75.Statements
76.static assert declaration
77.Static storage duration
78.Storage-class specifiers
79.string literals
80.Struct declaration
81.switch statement
82.Thread storage duration
83.Type
84.Type
85.Typedef declaration
86.Undefined behavior
87.Union declaration
88.Value categories
89.Variadic arguments
90.volatile type qualifier
91.while loop
92._Alignof operator
93._Noreturn function specifier
C

C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。