CU/xv?%rs9i{0 前言:51Testing软件测试网
DX.RGa,X+]4z0V
51Testing软件测试网+I.O]f;a.ay@.h 前日,在一次C++课程上,刘老师在举例说明构造函数和析构函数的功能时,提到了
全局变量初始化时的构造函数的行为。构造函数在main函数之前初始化全局变量。当然在C++下我是深信不疑的。但随后老师声称C语言下的全局变量也是如
此,因为C没有构造和析构函数,所以我们无法看到这一过程,在C++下可以在构造和析构函数中向屏幕打印信息,进而可以观察全局变量的初始化和生存期。
M2w9MQ*}5cp7l0Z'C!oV,TJM0 这个观点无疑使我心头一震,作为C的痴迷者,长期以来在我头脑中的印象是,全局变量在编译期就完成初始化了。难道我的观念是错误的?!难道C真的也是在main函数之前,在程序运行初期才初始化?!51Testing软件测试网/LI z*l3A(y!C,W4p
hP}L+{qIe-u+S0 于是我翻看了《C语言参考手册》这本书上没有明确的答案,再翻看著名的K&R的《C程序设计语言》中只有括号里面的一句话“在概念上.......”也是含糊其辞。(现在想想这个问题可能和编译器有关,所以丹爷爷也没说明太多)
\[9?.S}E
B051Testing软件测试网@/|3t
l)I+`b2U 在网上查询了一下,关于这个问题,持什么观点的都有,没有一个权威的答案。51Testing软件测试网(pj7B\2ig:Y/wu
51Testing软件测试网3t$c-h%~b,p 只能靠自己了,动手实验!51Testing软件测试网 e&f)hgd^
s"qx`LH.?
S
51Testing软件测试网9u4T7L/u!k#l ~ 先给出我的结论:51Testing软件测试网5G,JC l5a%h
51Testing软件测试网-D(NL.H;iw-oVQ
Q-N\ C和C++中的一般全局变量(不包括类class)是在编译期确定的初始值,而不是在程序运行时,在main函数之前初始化的。51Testing软件测试网 t/F ],~K+v:[^
`1~
51Testing软件测试网4n4I]bQ:Y`2b4Os` C++中的类的全局变量是在程序运行时,在main函数之前初始化的。
5LE0ad0X:eT051Testing软件测试网
dA6|;A)g 预热知识:
M
o
k
Mn!^Lc3L}051Testing软件测试网wI5t&knnb_
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函数代码51Testing软件测试网9BM+Ro{ D
51Testing软件测试网/Us|Q
x br1T&Pl+l 以VC++6.0为例设置:Project->Settings->Link 在Category中选择Output,在Entry-point symbol中填上main 即可。
k
m"f$c`yev0W6i u4G T@?0 -------------------------51Testing软件测试网M+Bh!cZ?
51Testing软件测试网*n)yo%Xv+rRa\e 实验一:51Testing软件测试网;gs"E.vIy4cb(~
51Testing软件测试网0V4j1RrB_ 1、C语言环境下:
E0H]A0Y9ao.E051Testing软件测试网%I+Q,l7R%sP%Rp#B@ 实验准备:
8kqD\;r0int a ;51Testing软件测试网$N'TH'XL&H6l7U int main(void)51Testing软件测试网:p4x_ Dn
S { /Vtn#|_+Q.n0 return a+3 ;51Testing软件测试网hw5YL$L } |
51Testing软件测试网t%UQ:D
Ix!Kf^6m 在编译器中设置入口函数为main(具体方法见上面)
Hv)M7n t@\;Uv051Testing软件测试网YBRbXK[QG 这样,我们让编译器生成的程序,直接从main函数中进入,而不是先执行mainCRTStartup函数做一些准备工作。51Testing软件测试网P5@"c(QO.d
51Testing软件测试网\P$Ya? u?%H 结果预测:
YKl X2ye0vT&Ex(t0 这样,如果函数返回的是3,则说明此全局变量是在编译期就被初始化为0了,如果函数返回的是其它数字,则说明此全局变量是在程序运行时,main函数运行前进行的初始化。51Testing软件测试网0j } L;_%q;u$`
51Testing软件测试网5cz/|"w.R @ 实验结果:51Testing软件测试网4yL-RgYH_T
51Testing软件测试网0O!r ]G \e#y"kD%m+y 进入控制台(运行cmd命令),运行编译后的程序(因为程序没有向屏幕输出结果,我们看不到任何现象),继续输入命令:echo %ERRORLEVEL% 则显示3,此即为函数的返回值。51Testing软件测试网?-}*`!Yo'q}
U
51Testing软件测试网P]s1?J&C"Sl (echo是显示其后的值,系统把前面运行的程序的返回值放在%ERRORLEVEL%中,故我们可以通过此方法获得主函数的返回值)
0U&]@-ct Y0i,Zd2e.o$k0 同理:对于结构体全局变量51Testing软件测试网1mRC6H&V}
8p7Psf4^~0
#K V7TLS a0struct A51Testing软件测试网;e%bSA!^N&U8PJ { H+hg h;kPyebH0 int a ; 51Testing软件测试网A}v-?(TYv-]/{ Kv } sTest; m+C)Aa$d
J7WV2I0int main(void) Z$?$q7_We(}p0{ S[qcb}s2g0 return sTest.a+3 ;51Testing软件测试网J[ h{Ew } |
?'\`P%N0\u
Y0}#Jx0 函数也返回3。51Testing软件测试网H(nHJtp
3Gv"V-y ]0 实验结论:
h6wuR C0b051Testing软件测试网5C4n@#NYG 在C语言中,全局变量是在编译期完成初始化的。51Testing软件测试网iXV*rYD
51Testing软件测试网~!a JMI3|.O$Z9S3h"Z C (在本实验中我们没有使用I/O函数把结果打印出来,因为I/O函数的调用之前必须要初始化内存中的某堆空间,而这个工作是由main函数之前的mainCRTStartup函数来做的。而我们设置让编译器跳过这个函数,故会在运行时出错。)51Testing软件测试网6AL
U7^7|6m t)gYs6J%b
7X"xzb5ir |4c
S0 实验二:51Testing软件测试网.FHQwg!qv#X6D
NQ
x?qE
[j/Syc0 C++语言环境下
{To,@$k]X{o0S*|\R eF0 实验准备:
}h:^1ag H-s0P#};vHza0
8I|C3asC5yu0class A 1qS4}n?S@k0{51Testing软件测试网*Q}6C6Y4B public: (gS$qA mR0 int a ; %aHc/g
oI P0 A(){a=10;}51Testing软件测试网'nB6SpQ_8Q ~A(){} "S}?wa(MJ(w0} ;51Testing软件测试网#x7dj/tA"a*e} A cTest ;51Testing软件测试网Se%W%u0},Z#w$V5O-q1~"p 51Testing软件测试网{Z&kl;x int main(void)51Testing软件测试网~!F,f(F"R N {51Testing软件测试网]kS8P5J:|{,Pz return cTest.a ; U"EC9r3i.P!j0} |
51Testing软件测试网!Cqc
v l 结果预测:
^g/Kw_nns7sz~0^"j iMu1E3yV(\0 这样,如果函数返回的是0,则说明此全局变量是在编译期就被初始化为0了,如果函数返回的是其它数字,则说明此全局变量是在程序运行时,main函数运行前进行的初始化。51Testing软件测试网0onH5`M.S
51Testing软件测试网M`%ePCp/Cv/~ 实验结果:
+y(a5q/k,Yz0`051Testing软件测试网+L_?4a+b 在编译器中设置入口函数为main,主函数返回一个其他值
;W"Ch^&gq2Y+]l051Testing软件测试网P|*D}:w1w5i 在编译器中设置入口函数为默认,主函数返回值为1051Testing软件测试网"])d&A5V'l
51Testing软件测试网L%@xhcK%h+K)r\ 实验结论:51Testing软件测试网Cw'Z uA0U
51Testing软件测试网)x]1f[q1o"O 在C++中,类(class)的全局变量是在程序运行期,main函数开始之前,调用类的构造函数完成初始化的。
0n
Bj-Ux6|0(};v\\3L/Q6`!E0 同理:51Testing软件测试网KO}8c2w4l
51Testing软件测试网$d'V;y;g^\a!U)I 把C中的代码放到C++下实验
#On|J~I051Testing软件测试网$h Rs$~.zh.z0tX4tg4tO#] w$c#O0int a ;
/W!C:hgh0int main(void)51Testing软件测试网^\0`J^:woLJ6cjC
{
8s,I?5gz w&]&q0 return a+3 ;
D'D5B*}2na*B!u m0}
"qj n;P"@0(y,z-jO-Q)lA~0 结果与C的结果相同。51Testing软件测试网7A6N p;R;ZV,E8i
*F!eo~;mm0 说明:在C++中一般全局变量的初始化(类除外),是在编译期完成的,而不是在运行期完成。(与C语言规则相同)51Testing软件测试网 b$d
s!V8_*{W3D%W
51Testing软件测试网/zwnU"N mainCRTStartup函数不管一般全局变量的初始化,它管理类(class)的全局变量的初始化,调用类的析构函数。51Testing软件测试网(v7N5\2yz[G%ej
"_U8oi0q0 编译器会在编译时,初始化一般全局变量为0.51Testing软件测试网 S)N
y!I5e(lW
G{x9fY0 另:具有全局生命期的局部静态变量的初始化,与局部变量相同都是在运行时,执行到该初始化语句完成初始化的,只是局部静态变量只初始化一次。51Testing软件测试网x
^3PIebW
51Testing软件测试网D#^ J3NI
[1t+{Dw 后记:51Testing软件测试网1h0[ }"J!N
"M"U$Nq2K8XN0 1、程序不是从主函数开始执行的,而是先要执行一些启动代码。(现在明白为什么要在在嵌入式软件编程时要在工程中添加类似于75x_init.s和75x_vect.s这两个汇编文件了吧)51Testing软件测试网,D5D6j
W6UmF T
51Testing软件测试网fYwO-I Q+g^ 2、你应该给主函数以返回值。实际上标准C只规定了两种形式的main函数:
Fn,dLdX(r4wO051Testing软件测试网6jd1g\9M int main(void) 和 int main(int argc, char *argv[])51Testing软件测试网'q6W6rZY
51Testing软件测试网V^ZWQ'@r main返回0,告诉系统程序正常终止,返回非零值告诉系统程序异常关闭.51Testing软件测试网c1[a6\"\}Y7RZ
51Testing软件测试网2ZC-V${l-WM9_ 其作用:我们可以利用程序的返回值,控制要不要执行下一个程序。51Testing软件测试网$tttp
~&_4?p0n
51Testing软件测试网wsYQ y1\ l 例:程序名&&DOS命令
*?/B:U}Z}0;}Z5l
`"Y$y0QX3_
_0 前面的程序正常执行后才执行后面的DOS命令。当然我们也可以用其它的逻辑符把程序和命令组织起来,来实现复杂的功能。
Q9M5yMK
| IS B00etlO1K*Eej0 (UNIX中的shell命令也有类似功能)51Testing软件测试网9Uu7FTiK`q
51Testing软件测试网 |;o
E(~H