为什么C语言全局变量初始化元素必须是常量,而局部变量可以不是常量

简介: 为什么C语言全局变量初始化元素必须是常量,而局部变量可以不是常量

前言

(1)今天看到一个有意思的问题,在交流群中,一位网友问,全局变量为什么不能给变量。会出现initializer element is not constant报错,代码如下

#include <stdio.h>
int a = 1;
int b = a+1; //这里会报错initializer element is not constant
int main(void)
{
  printf("a = %d\r\n",a);
  printf("b = %d\r\n",b);
  return 0;
}

(2)一般来说,全局变量我们都是默认给的一个常量数字,局部变量赋值给一个变量。关于上述问题,我也表示疑惑,于是我带着疑问,开始查找资料。

#include <stdio.h>
int a = 1;
int main(void)
{
  int b = a+1;
  printf("a = %d\r\n",a);
  printf("b = %d\r\n",b);
  return 0;
}


解释

全局变量和局部变量存储位置

(1)想要弄清楚这个问题,首先,我们需要知道全局变量和局部变量存储有什么区别?想了解具体信息,请看:RAM明明断电会丢失数据,为什么初始化的全局变量存储在RAM?详细分析程序的存储;

(2)因为上面的文章篇幅比较大,所以我浓缩一下。

<1>被赋值为非0的全局变量,最终会存储在.data段。他在编译时候,会变成RW-data,他的初始值是需要存储在ROM区域的。

<2>而局部变量,并不会被编译进入单片机,也就是说,他在单片机断电状态是不占空间的。

<3>当单片机上电之后,会给全局变量在RAM中分配出一个静态数据区。同时把初值赋值到这个静态数据区的.data段。

<4>单片机上电并且开始运行程序之后,调用到了局部变量所存在的那个函数时候。单片机才会给局部变量在栈中分配空间,然后赋初值是在运行过程中,执行代码实现的。

<5>因此,我们可以得出结论。被赋初值的全局变量,初始值是静态存储。而被赋初值的局部变量,初始值是动态存储。

(4)了解了上述之后,我们就能够明白为什么局部变量赋初始值可以被通过了,因为他是动态的,所以编译器不会管他。但是为什么全局变量又不可以呢?这就涉及,静态存储的数据与编译器之间的关系了。


编译器有关

(1)我们都知道,编译器能够将C语言变成机器所能够识别的01语言。而编译器的还有一些功能,常常被我们所忽视了。

(2)为了能够让程序更加小巧精炼,编译器会帮我们处理很多事情。这就引出了一个概念,用编译器的时间换运行态的时间。

<1>编译时:您(开发人员)编译代码的时间段。

<2>运行时间:用户运行您的软件的时间段。

(3)例如下面这个简单的代码:

<1>我们能够发现int b = 2 + 3;转换称为汇编代码之后,他是直接将5传递给了b。这个就是编译器进行了运算处理,对代码进行了优化。这个叫做常量折叠。

<2>sizeof这个运算同理,编译器会直接将int是4个字节这个信息传递给变量。


(4)上述两个例子都是用编译器的时间换运行态的时间。那么讲了这么多,和全局变量初始化元素必须是常量有什么关系呢?

(5)上面说了,编译器会进行常量折叠,但是请注意,这里是常量折叠!常量折叠会将常量表达式在编译器运行时期计算出来,整型字面量、sizeof()运算符(当参数不是VLA时),枚举常量,以及各种算术、关系/比较运算符在所有操作数都是整型常量时,整个表达式都会算是整型常量表达式。


(6)但是,我们发现了没有,编译器是不会进行变量的运算的!因此,全局变量int b = a+1;这样赋初值,编译器是不会进行运算的!

总结

(1)因此,我们可以得出结论:

<1>编译器无法在编译时求得一个非常量的值,它只能在运行时通过读取变量地址来间接得到变量的值,而全局变量在编译时就必须确定其值。

<2>局部变量的初始值是不由编译器管理,他是在运行时进行的分配,因此可以初值可以赋予变量。

目录
相关文章
|
10天前
|
存储 算法 C语言
【C语言】字符常量详解
字符常量是C语言中处理字符数据的重要工具。通过单引号括起一个字符,我们可以方便地使用字符常量进行字符判断、字符运算和字符串处理等操作。理解字符常量的表示方法、使用场景和ASCII码对应关系,对于编写高效的C语言程序至关重要。
58 11
|
10天前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
32 7
|
10天前
|
C语言
【C语言】<常量> 之群英荟萃
在C语言中,常量(Constants)是指在程序运行过程中其值不能被修改的固定值。常量包括数值常量(整型和浮点型)、字符常量、字符串常量、使用const关键字定义的常量变量以及枚举常量。
19 4
|
10天前
|
编译器 C语言
【C语言】常量的 “前缀和后缀” 大通关!
在C语言中,常量的前缀和后缀用于明确指定常量的类型和进制系统。前缀主要用于区分不同进制的数字常量,而后缀则用于区分不同类型的整数和浮点数。正确使用前缀和后缀,可以提高代码的可读性和可维护性,确保编译器正确地理解和处理常量。
23 1
|
14天前
|
存储 算法 C语言
C语言中常见的字符串处理技巧,包括字符串的定义、初始化、输入输出、长度计算、比较、查找与替换、拼接、截取、转换、遍历及注意事项
本文深入探讨了C语言中常见的字符串处理技巧,包括字符串的定义、初始化、输入输出、长度计算、比较、查找与替换、拼接、截取、转换、遍历及注意事项,并通过案例分析展示了实际应用,旨在帮助读者提高编程效率和代码质量。
49 4
|
2月前
|
编译器 C语言
C语言:普通全局变量可以被多个源文件共享吗
C语言中,普通全局变量可以通过extern关键字在多个源文件中声明和共享,实现数据的跨文件使用。但需注意,变量只能在一个文件中定义,其他文件中仅能声明。
|
2月前
|
存储 C语言
C语言:普通局部变量、普通全局变量、静态局部变量、静态全局变量的区别
C语言中,普通局部变量在函数内部定义,作用域仅限于该函数;普通全局变量在所有函数外部定义,作用域为整个文件;静态局部变量在函数内部定义但生命周期为整个程序运行期;静态全局变量在所有函数外部定义,但仅在定义它的文件内可见。
97 10
|
2月前
|
存储 C语言
C语言:一维数组的不初始化、部分初始化、完全初始化的不同点
C语言中一维数组的初始化有三种情况:不初始化时,数组元素的值是随机的;部分初始化时,未指定的元素会被自动赋值为0;完全初始化时,所有元素都被赋予了初始值。
|
2月前
|
存储 C语言
初识C语言:常量与变量中寻找数据类型
初识C语言:常量与变量中寻找数据类型
|
3月前
|
存储 C语言
【C语言基础考研向】02 数据类型-常量-变量
本文介绍了编程中的基本概念,包括数据类型分类、常量与变量的定义及使用。首先概述了四大类数据类型:基本类型(整型、浮点、字符型)、构造类型(数组、结构体)、指针类型和空类型。接着阐述了常量与变量的区别及命名规则,并详细说明了整型、浮点型和字符型数据的特点与应用。最后总结了常见的易错点,如字符串与字符常量的区别及浮点数的默认输出格式。