关于C/C++中全局变量的初始化问题的深入思考

C C++全局变量初始化 initializer element is not constant 错误 C C++全局变量初始化 initializer element is not constant 错误 c++中为什么不能对全局变量在函数外赋值 http://blog.csdn.net/abc78400123/article/details/6766947 分类: C语言基础2011-09-11 09:28 595人阅读 评论(0) 收藏 举报 c++c编译器i 阅读详情

前言:

前日,在一次C++课程上,刘老师在举例说明构造函数和析构函数的功能时,提到了全局变量初始化时的构造函数的行为。构造函数在main函数之前初始化全局变量。当然在C++下我是深信不疑的。但随后老师声称C语言下的全局变量也是如此,因为C没有构造和析构函数,所以我们无法看到这一过程,在C++下可以在构造和析构函数中向屏幕打印信息,进而可以观察全局变量的初始化和生存期。

这个观点无疑使我心头一震,作为C的痴迷者,长期以来在我头脑中的印象是,全局变量在编译期就完成初始化了。难道我的观念是错误的?!难道C真的也是在main函数之前,在程序运行初期才初始化?!

于是我翻看了《C语言参考手册》这本书上没有明确的答案,再翻看著名的K&R的《C程序设计语言》中只有括号里面的一句话“在概念上.......”也是含糊其辞。(现在想想这个问题可能和编译器有关,所以丹爷爷也没说明太多)

在网上查询了一下,关于这个问题,持什么观点的都有,没有一个权威的答案。

只能靠自己了,动手实验!

 

先给出我的结论:

C和C++中的一般全局变量(不包括类class)是在编译期确定的初始值,而不是在程序运行时,在main函数之前初始化的。

C++中的类的全局变量是在程序运行时,在main函数之前初始化的。

 

预热知识:

C或者C++语言,明面上的入口函数是main(argc,argv),或者tmain、wmain、WinMain等等。但实际上,是C Runtime的startup代码中的void mainCRTStartup(void)函数,调用了编程者写的main函数。这个函数定义在VisualC++安装目录的crt\src\目录下的某个.c文件中(视VC++的版本不同,存放的文件也不同)。它在执行一些初始化操作,如获取命令行参数、获取环境变量值、初始化全局变量、初始化io的所需各项准备之后,调用main(argc,argv)。main函数返回后,mainCRTStartup还需要调用全局变量的析构函数或者atexit()所登记的一些函数。往深里说,是在链接生成可执行文件时,告诉链接器这个可执行文件的entry就是mainCRTStartup。当然,我们也可以对编译器进行设置,使其不插入mainCRTStartup函数代码

以VC++6.0为例设置:Project->Settings->Link 在Category中选择Output,在Entry-point symbol中填上main 即可。

-------------------------

实验一:

1,     C语言环境下:

实验准备:

int a ;
int main(void)
{
       return a+3 ;
}

在编译器中设置入口函数为main(具体方法见上面)

这样,我们让编译器生成的程序,直接从main函数中进入,而不是先执行mainCRTStartup函数做一些准备工作。

结果预测:

这样,如果函数返回的是3,则说明此全局变量是在编译期就被初始化为0了,如果函数返回的是其它数字,则说明此全局变量是在程序运行时,main函数运行前进行的初始化。

实验结果:

进入控制台(运行cmd命令),运行编译后的程序(因为程序没有向屏幕输出结果,我们看不到任何现象),继续输入命令:echo  %ERRORLEVEL% 则显示3,此即为函数的返回值。

(echo是显示其后的值,系统把前面运行的程序的返回值放在%ERRORLEVEL%中,故我们可以通过此方法获得主函数的返回值)

 

同理:对于结构体全局变量

struct A
{
       int a ;     
} sTest;
int main(void)
{
       return sTest.a+3 ;
}

函数也返回3.


实验结论:

在C语言中,全局变量是在编译期完成初始化的。

(在本实验中我们没有使用I/O函数把结果打印出来,因为I/O函数的调用之前必须要初始化内存中的某堆空间,而这个工作是由main函数之前的mainCRTStartup函数来做的。而我们设置让编译器跳过这个函数,故会在运行时出错。)

 

实验二:

C++语言环境下

实验准备:

class A
{
public:
       int a ;     
       A(){a=10;}
       ~A(){}
} ;
A cTest ;
 
int main(void)
{
       return cTest.a ;
}

结果预测:

这样,如果函数返回的是0,则说明此全局变量是在编译期就被初始化为0了,如果函数返回的是其它数字,则说明此全局变量是在程序运行时,main函数运行前进行的初始化。

 

实验结果:

在编译器中设置入口函数为main,主函数返回一个其他值

在编译器中设置入口函数为默认,主函数返回值为10

实验结论:

在C++中,类(class)的全局变量是在程序运行期,main函数开始之前,调用类的构造函数完成初始化的。

同理:

把C中的代码放到C++下实验

int a ;
int main(void)
{
       return a+3 ;
}

结果与C的结果相同。

说明:在C++中一般全局变量的初始化(类除外),是在编译期完成的,而不是在运行期完成。(与C语言规则相同)

mainCRTStartup函数不管一般全局变量的初始化,它管理类(class)的全局变量的初始化,调用类的析构函数。

编译器会在编译时,初始化一般全局变量为0.

 

 

另:具有全局生命期的局部静态变量的初始化,与局部变量相同都是在运行时,执行到该初始化语句完成初始化的,只是局部静态变量只初始化一次。

 

后记:

1、程序不是从主函数开始执行的,而是先要执行一些启动代码。(现在明白为什么要在在嵌入式软件编程时要在工程中添加类似于75x_init.s和75x_vect.s这两个汇编文件了吧)

2、你应该给主函数以返回值。实际上标准C只规定了两种形式的main函数:

int main( void ) 和 int main(int argc, char *argv[])

main返回0,告诉系统程序正常终止,返回非零值告诉系统程序异常关闭.

其作用:我们可以利用程序的返回值,控制要不要执行下一个程序。

例:程序名&&DOS命令

前面的程序正常执行后才执行后面的DOS命令。当然我们也可以用其它的逻辑符把程序和命令组织起来,来实现复杂的功能。

(UNIX中的shell命令也有类似功能)

 

 

 

C++全局变量初始化的一点总结 注意:本文所说的全局变量指的是 variables with static storage,措词来自 c++ 的语言标准文档。   什么时候初始化   根据 C++ 标准,全局变量的初始化要在 main 函数执行前完成,常识无疑,但是这个说法有点含糊,main 函数执行前到底具体是什么时候呢?是编译时还是运行时?答案是既有编译时,也可能会有运行时(seriously), 从语言的层面来说,全局变量的初始化可以认为分成以下两个阶段(c++11 N3690 3.6.2):   static initialization: 静态初始化指的是用常量来对变量进行初始化,主要包括 zero init 立即下载

相关推荐

从零开始:如何用Python手绘波特图并分析电路稳定性

本文详细介绍了如何使用Python绘制波特图并分析电路稳定性,涵盖从基础理论到实际应用的完整流程。通过NumPy和Matplotlib实现频域分析,包括RC低通滤波器和RLC带通滤波器的案例,以及相位裕度计算等高级技巧,为电子工程师提供了一套高效的电路分析解决方案。

hhh00的博客 366

C\C++编程技巧之全局变量的初始化

考虑到如果第一次变量dis就是0的话,该动作并不会执行。故需要在上电初始化的时候,将该值设置为不相等,不要将dis_old值置为某一个特定的值,不然会出现特定的bug。

qq_28116937的博客 831

MRI图像切片(nii格式转2D)

代码参考:将一个MRI(nii格式)数据进行切片 想要批量抽取MRI数据的几个切片,借鉴了上述代码的Python版本,原始代码抽取了全部切片。本次实验主要是抽取sMRI的横断面(axial)方向的其中30张切片,数量根据自己需求可自行设置。 import scipy, numpy, shutil, os, nibabel import sys, getopt import imageio def niito2D(filepath): inputfiles = os.listdir(filep

chs_502的博客 7537

C++全局变量的初始化过程

全局变量在main()前完成初始化(调用构造函数) 在调用构造函数前,全局变量已分配空间,内存全0 多个全局变量的初始化,按照代码编译的顺序 注意:全局变量被访问前可能它还没有调用构造函数初始化。 如果一个项目中,多个dll都用到一个全局变量在共同的lib中,则每个dll都有一个独立的全局变量(地址不同),每个全局变量会初始化。 如下代码,A里面访问了全局变量g_b, 改变全局变量g_a...

vcpro126的专栏 2459

用树莓派Pico低成本更新USB-C PD控制器固件实战指南

固件更新是嵌入式系统开发与维护中的核心环节,它直接决定了硬件设备的功能、性能与兼容性。其原理通常是通过特定的通信接口(如SWD、JTAG、UART或USB)与设备内部的Bootloader建立连接,将新的程序代码安全写入非易失性存储器。在USB Power Delivery(PD)和Type-C生态中,固件更新技术尤为重要,它能修复协议握手Bug、适配新设备并提升供电策略的灵活性。本文聚焦于一个典型的工程实践场景:如何利用广泛普及且成本极低的树莓派Pico开发板,作为USB-C协议到I²C协议的转换桥,实现

weixin_27869497的博客 442

国产麒麟系统下Kettle安装避坑指南:解决aarch64架构不支持问题

本文详细解析了在国产麒麟系统上部署Kettle时遇到的aarch64架构不支持问题,提供了从获取适配的SWT库、修改启动脚本到生产环境调优的完整解决方案。文章重点解决了ARM架构与Java GUI工具的兼容性挑战,并分享了内存配置、字体显示及Carte服务部署等实战经验,助力用户在国产化环境中稳定运行ETL流程。

weixin_29197835的博客 552

跟我学c++中级篇——静态(全局)变量初始化依赖

一、问题的现象 实际的项目代码中遇到一个很疑惑的问题,问题可以描述为:一个静态成员初始化的时候直接core掉,该静态成员初始化时通过另外一个文件中静态成员来完成。该问题同样发生在全局对象上。 具体可以用代码简述如下: //test1.cpp #include<string> std::stringa="test"; //test2.cpp #include<iostream> externstd::stringa; std::stringb=a; int...

fpcc的专栏 3119

DS18B20温度传感器项目实战:从驱动编写到LCD显示,打造你的第一个温控系统

本文详细介绍了如何使用DS18B20温度传感器和LCD1602显示屏构建一个完整的温控系统。从硬件连接、OneWire协议实现到温度数据采集与LCD显示,全面解析了系统整合与工程化实现的关键步骤,帮助开发者快速掌握嵌入式温度监测系统的开发技巧。

weixin_42525328的博客 347

C++ 变量初始化顺序

1.全局变量初始化顺序 什么时候初始化 根据 C++ 标准,全局变量的初始化要在 main 函数执行前完成,常识无疑,但是这个说法有点含糊,main 函数执行前到底具体是什么时候呢?是编译时还是运行时?答案是既有编译时,也可能会有运行时(seriously), 从语言的层面来说,全局变量的初始化可以划分为以下两个阶段(c++11 N3690 3.6.2): static initialization: 静态初始化指的是用常量来对变量进行初始化,主要包括 zero initialization 和 con

lin的博客 3507

SPSS(二)SPSS实现多因素方差分析模型(图文教程+数据集)

SPSS(二)SPSS实现多因素方差分析模型 单因素方差分析上一篇博客https://blog.csdn.net/LuYi_WeiLin/article/details/89917656已经介绍完毕 这篇博客我们主要来学习多因素方差分析 多因素方差分析,就是同时考虑若干个控制因素的情况下,分别分析它们的改变是否造成观察变量的显著变动 (多个自变量,一个因变量)自变量类型以分类变量为主也可以...

可乐联盟 6万+

Altium Designer (AD) 设计软件高频面试题及参考答案(3万字长文)

在Altium Designer(AD)中,设计复用是一种关键的策略,它允许设计师在多个项目中重复使用经过验证的设计元素,如原理图符号、PCB布局、元器件封装和设计规则集。在Altium Designer (AD) 中,手动布线和交互式布线是PCB设计中常见的两种布线模式,它们提供了设计师对布线路径的直接控制,特别是在处理复杂或关键信号路径时尤为有用。在Altium Designer (AD) 中进行电路级仿真是一项重要的设计验证步骤,它允许设计师在实际制造之前对电路的行为进行预测和分析。

大模型大数据攻城狮的专栏 4771

C/C++ --- 全局变量初始化总结

注意:本文所说的全局变量指的是 variables with static storage,措词来自 c++ 的语言标准文档。 什么时候初始化 根据 C++ 标准,全局变量的初始化要在 main 函数执行前完成,常识无疑,但是这个说法有点含糊,main 函数执行前到底具体是什么时候呢?是编译时还是运行时?答案是既有编译时,也可能会有运行时(seriously), 从语言的层面来说,全局

xl928471061的博客 5573

RK3568 Android14 移远GNSS卫星导航模组LC760Z GPS北斗定位模块调试

Rockchip RK3568 作为一款高性能、低功耗的国产SoC,被广泛应用于工业网关、车载中控和智能手持终端等领域。在这些应用场景中,位置服务(Location Service) 往往是不可或缺的功能。本文将详细记录如何集成GPS模组到 RK3568 开发板上,通过 UART(串口)接口集成通用的 GPS 模块(如 移远LC760Z 或 EC20 4G 模块自带的 GPS 功能也差不多),并实现数据的解析与上层应用对接。

qq_33427070的博客 1403

C++全局对象的初始化顺序问题思考

问题产生: 在代码中的某个头文件定了几个全局的 const std::string ,同时定义了某个类,在类的构造函数中使用了这几个全局变量。 该类作为单例模板的成员被使用了,单例的编译在另外一个单元。 程序编译链接正常,运行时候segment fault gdb调试const 成员变量,内存不可访问 分析该问题需要具备的基础知识: 知识一: 全局变量、文件域的静态变量和类的静态...

veghlreywg的博客 2045

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

C/C++:调用函数来初始化全局变量

C/C++:调用函数来初始化全局变量

test1280 3351

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

c语言数组初始化只能常量,C语言全局变量的初始化和字符串常量

在C++中对于以下语句:// 全局域int i = 3;int j = i;编译时将i放入.data段,设置其值为3。而对于j,编译器遇到这种语句,只知道j = i,由于i是变量,不是常量,编译器无法在编译时直接得到它的值,编译器只会找到i的地址, 然后读取这个地址的内容,再把这个内容写入j的地址。编译器不能够直接用3来初始化j,因为计算机不是人,不懂简单的人类逻辑,我们想“因为i = 3,而j ...

weixin_39541227的博客 1403

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

c 初始化char**_C/C++内存模型

不知道你有没有想过什么是程序?程序 = 数据结构 + 算法再往内部粗略的理解,计算机硬件只能识别0和1这两种数字量,非0即1,非黑即白当然今天不探讨这些,主要聊一聊程序中的数据在内存中存放的位置及形式,相信这会对进一步理解程序有一定的帮助!主要来源于网络,如有不正确的地方,望大家不吝指正。参考文章:https://blog.csdn.net/second60/article/details/799...

weixin_35315019的博客 523

C C++全局变量初始化 initializer element is not constant 错误 c++中为什么不能对全局变量在函数外赋值

***(行号):error: initializer element is not constant ***(行号):error: (near initialization for `**') c标准:全局变量(external variable)和静态变量 (stati

3149

你真的懂C语言启动流程吗?,全局变量初始化顺序全解析

掌握C语言启动流程的关键,解析C语言中全局变量的初始化顺序。涵盖编译期初始化、未初始化变量处理及构造函数调用顺序,适用于嵌入式开发与程序启动优化。理解底层机制,提升代码可靠性,值得收藏。

AlgoFun的博客 691

全局变量与局部变量优先级调用的问题—C/C++程序基础(二)

C++中定义的函数,必须有输入参数(或者说是,形参列表)。 在main函数中,当局部变量和全局变量同时存在的时候,优先引用局部变量,而不去引用全局变量。 "::"这个符号,可以直接来操作全局变量的。

恋蛩音的博客 4343

c++ 全局变量初始化的一点总结

注意:本文所说的全局变量指的是 variables with static storage,措词来自 c++ 的语言标准文档。 什么时候初始化 根据 C++ 标准,全局变量的初始化要在 main 函数执行前完成,常识无疑,但是这个说法有点含糊,main 函数执行前到底具体是什么时候呢?是编译时还是运行时?答案是既有编译时,也可能会有运行时(seriously), 从语言的层面来说,全局变量的初始化...

weixin_34161032的博客 741

what does before main----C/C++ RTL 解析

文章目录what does before main----C/C++ RTL 解析运行时库实现的功能,在main函数执行之前都做了什么思考:二、运行时库概述三、运行时库主要功能模块四、程序详细运行过程1 程序执行前装载器把用户的参数和环境变量压入栈,2 初始化和OS版本相关的全局变量3 初始化堆,每个进程都有属于自己的堆。4 I/O初始化,继承父打开文件表。5. 获取命令行参数和环境变量6. 初...

fgh123的博客 717

全局变量、局部变量和静态变量

全局变量、局部变量和静态变量

qq_38616059的博客 7719

c语言 全局字符串变量名,C语言全局变量的初始化和字符串常量

在C++中对于以下语句:// 全局域int i = 3;int j = i;编译时将i放入.data段,设置其值为3。而对于j,编译器遇到这种语句,只知道j = i,由于i是变量,不是常量,编译器无法在编译时直接得到它的值,编译器只会找到i的地址, 然后读取这个地址的内容,再把这个内容写入j的地址。编译器不能够直接用3来初始化j,因为计算机不是人,不懂简单的人类逻辑,我们想“因为i = 3,而j ...

weixin_39787057的博客 758

c/c++中一个 类似 a[2] 的数组引发的一些思考

今天写了如下几行代码: 其中CutTaskLine 是一个结构体, M_TASK_MAX是 #define M_TASK_MAX 4096 CutTaskLine CutItemD_out[M_TASK_MAX]; memset(CutItemD_out, 0x00, sizeof(CutTaskLine)*M_TASK_MAX); 上面这两行代码是在一个一个函数内使用的,编译无错误...

积累点滴,保持自我 764
上一篇: C语言精华记录——捌(预处理、程序调试、编程风格)
下一篇: C++对象模型简介(一)——《深度探索C++对象模型》精简笔记
Moo-Yan
博客等级 码龄14年 973粉丝 68原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值