c进阶篇(十一)——变量初始化详解

前言:
   定义变量时对数据类型进行初始化是十分有必要的,但变量的初始化也许还有你不知道的细节,本篇文章带你深入探讨。

1 静态、局部和全局变量初始化

  我们把变量按照作用域和生存期进行分类,可以分为静态变量、局部变量、全局变量三类。定义变量时从语法上将可以对变量初始值进行初始化,也可以选择不初始化,以下进行未初始化时初值探究。

1.1 未初始化时的初值

  未初始化时,由于全局变量和静态变量由编译器自动初始化为0(仍然建议代码上写明初始值赋值0),而局部变量存储在栈空间里,未初始化时初值是不确定的。这里以byte类型(uint8_t)举例,其他数据类型也一样(指整形、浮点型、字符型、指针型、数组、结构体、联合体、枚举)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
byte g_byTmp; //全局变量。

byte Fun(void)
{
static byte s_byTmp; //静态变量。
byte byTmp; //局部变量。

return byTmp + g_byTmp + s_byTmp;
}

int32_t main(void)
{
Fun();

while(1u);
}

No_Set.png

1.1 初始化后的初值

  基础数据类型初始化后的初值就是代码所阈值的值(似乎是废话!),但几种特殊的数据类型除外(数组、结构体、联合),因为这些特殊的数据类型能有多个成员,会出现“初始化不完全”的情况,那么剩余的未被初始化的变量初始值是什么就是一个问题。
  由于数据类型作为全局或静态变量时,编译器会自动将其初始化为0,因此以下探究的都是数据类型作为局部变量的情况。

1.1.1 部分元素初始化

  当为数组、结构体、联合等具有多个元素的数据类型进行初始化时,若只对其部分元素进行初始化(初始值可为0或非0),则剩余的元素也会被编译器初始化为0。

形式1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
typedef struct
{
byte byTmp;
word wTmp;
dword dwTmp;
}TTmp;

typedef union
{
byte byTmp;
word wTmp;
dword dwTmp;
}UTmp;

byte Fun(void)
{
byte abyTmp[3u] = {1u};
TTmp tTmp = {2u};
UTmp uTmp = {3u};

return abyTmp[0u] + tTmp.byTmp + uTmp.byTmp;
}

int32_t main(void)
{
Fun();

while(1u);
}

First_Set.png

形式2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
typedef struct
{
byte byTmp;
word wTmp;
dword dwTmp;
}TTmp;

typedef union
{
byte byTmp;
word wTmp;
dword dwTmp;
}UTmp;

byte Fun(void)
{
byte abyTmp[3u] = {1u};
TTmp tTmp = {.wTmp = 2u}; //显式指定一个元素初始化。
UTmp uTmp = {.wTmp = 3u}; //显式指定一个元素初始化。

return abyTmp[0u] + tTmp.wTmp + uTmp.wTmp;
}

int32_t main(void)
{
Fun();

while(1u);
}

  结构体可以显式只指定部分元素初始化,未初始化的其他元素也会被编译器初始化为0。

1.1.2 未指定大小的数组元素初始化

  数组在定义时可以不给出元素个数,最终个数取决于定义时初始化的元素个数。这时元素的初始值也由初始化的参数决定。

1
2
3
4
5
6
7
8
9
10
11
12
13
byte Fun(void)
{
byte abyTmp[] = {1u, 2u, 3u};

return abyTmp[0u];
}

int32_t main(void)
{
Fun();

while(1u);
}

Array.png