请教:变量到底是在编译的时候初始化的,还是在运行的时候初始化的?

learnc2015 2015-09-21 01:23:12
变量到底是在编译的时候初始化的,还是在运行的时候初始化的?
如下函数:居然调用两次打印出来的值分别是1和2,非常不好理解
如果按照C PRIMER PLUS说的这样的变量是在编译的时候初始化的,
实在令人难以理解,编译只是生成了可执行文件而已
何来在内存里分配了空间并赋值?

int f (void)
{
static int mm=1;
mm++;
printf("%d\n",mm);
}
...全文
1869 48 打赏 收藏 转发到动态 举报
写回复
用AI写文章
48 条回复
切换为时间正序
请发表友善的回复…
发表回复
man122 2016-09-23
  • 打赏
  • 举报
回复
不是应该打印2,3 吗?为啥是1, 2~!
「已注销」 2015-09-28
  • 打赏
  • 举报
回复
代码:
int f (void)
{
    static int mm=1;
    mm++;
    printf("%d\n",mm);
}
可以理解为:
int mm=1;
int f (void)
{
    mm++;
    printf("%d\n",mm);
}
且 mm 仅在函数 f 内可见
zeloas 2015-09-27
  • 打赏
  • 举报
回复
引用 5 楼 zhao4zhong1 的回复:
有的变量是在编译的时候初始化的,有的变量是在运行的时候初始化的。
通常编译时能够进行的计算编译时就完成了, 如常量计算一类的
均陵鼠侠 2015-09-23
  • 打赏
  • 举报
回复
引用 42 楼 worldy 的回复:
[quote=引用 40 楼 sholber 的回复:] [quote=引用 37 楼 worldy 的回复:] [quote=引用 14 楼 sholber 的回复:] [quote=引用 11 楼 zhao4zhong1 的回复:] 编译的时候没初始化,那代码段汇编指令中的常量是谁写上去的?
1,汇编指令中还有常量,这个没听说过; 2,初始化是什么意思,赵老师学C数十载,竟然到现在还没弄明白。 赵老湿以为朕是外国人,不懂中国话吗![/quote] 编译器写的,比如函数体中有 static n=100; n=n++; 编译器会将n放到程序读数据段的某个磁盘单元并且将其值设置为100,exe被加载的时候,整个数据段会原封不动的加载到内存,因此和n对应的存储单元就有100的起始值 [/quote] 首先,你所说的,是业界流行的做法,但流行不代表就是确凿证据。人人都走阳关大道和捷径,但驴友就喜欢走没有路的偏僻丛林,你说不行?如果编译器只在EXE里为n保留一个位置,然后在程序开始执行的时候才用mov指针加一个立即数将100写到n对应的存储单元,难道不行? 其次,初始化这个词本身就没找到完整的定义,讨论起来自然各说各的。就像你说的,整个数据段加载到内存,这个覆盖内存原来东西的操作,不能叫初始化? 最后,n=n++不是一个有确定行为的表达式,赵老师会让你看置顶帖的。[/quote] 按照你的MOV方法进行初始化,那如果我初始化的是一个表呢?编译器创建一个循环还是一个数据生成一条初始化指令? n=n++是我写错了,你也不用太在意 [/quote] 干嘛钻牛角尖,我的意思很简单,不要拿C实现的细节,什么段啊、堆啊栈啊说事,解决这个问题不需要这些东西,解决C的问题也不需要钻到这个层次。 好吧,如果是初始化一个表,这个表及其元素都只具有自动存储期,那么,我宁愿使用MOV指令的序列。
worldy 2015-09-23
  • 打赏
  • 举报
回复
引用 40 楼 sholber 的回复:
[quote=引用 37 楼 worldy 的回复:] [quote=引用 14 楼 sholber 的回复:] [quote=引用 11 楼 zhao4zhong1 的回复:] 编译的时候没初始化,那代码段汇编指令中的常量是谁写上去的?
1,汇编指令中还有常量,这个没听说过; 2,初始化是什么意思,赵老师学C数十载,竟然到现在还没弄明白。 赵老湿以为朕是外国人,不懂中国话吗![/quote] 编译器写的,比如函数体中有 static n=100; n=n++; 编译器会将n放到程序读数据段的某个磁盘单元并且将其值设置为100,exe被加载的时候,整个数据段会原封不动的加载到内存,因此和n对应的存储单元就有100的起始值 [/quote] 首先,你所说的,是业界流行的做法,但流行不代表就是确凿证据。人人都走阳关大道和捷径,但驴友就喜欢走没有路的偏僻丛林,你说不行?如果编译器只在EXE里为n保留一个位置,然后在程序开始执行的时候才用mov指针加一个立即数将100写到n对应的存储单元,难道不行? 其次,初始化这个词本身就没找到完整的定义,讨论起来自然各说各的。就像你说的,整个数据段加载到内存,这个覆盖内存原来东西的操作,不能叫初始化? 最后,n=n++不是一个有确定行为的表达式,赵老师会让你看置顶帖的。[/quote] 按照你的MOV方法进行初始化,那如果我初始化的是一个表呢?编译器创建一个循环还是一个数据生成一条初始化指令? n=n++是我写错了,你也不用太在意
kingtown11 2015-09-23
  • 打赏
  • 举报
回复
静态和全局变量的初始化操作确实是编译后保存在文件中的。 具体实验方法可以用二进制修改器,修改EXE中静态变量的值,然后直接启动EXE看是原来未修改的值,还是修改后的值。 程序加载后,会在main函数之前将各种数据初始化,其中也包括着全局和静态。 PE里面也可以看出来,前面有人讲过了,不阐述了。。 汇编前面看大家讨论了这么多,就不参合了,其实全局变量赋值的形式就是一个偏移地址的值,反汇编看的话其实唯一的区别是main函数前还是main函数后给的,进入main函数前就赋值到内存里了的话,就是说明程序在加载入内存的时候,全局变量已经有值了。 不过这个不具代表性,因为如果是自定义程序入口函数,自己裁剪一下一切皆有可能。
均陵鼠侠 2015-09-22
  • 打赏
  • 举报
回复
引用 31 楼 zhao4zhong1 的回复:
闲来无事去读读gcc或g++源代码killtime吧。
读killtimr? 赵老师的意思是他很渊博,视野开阔,看了不少源代码。但他忘了,正是他象老婆婆一样,总在劝大家不轻信、不盲从。信别人不信sholber,赵老师看来并不如他自诩的那样客观罢。
赵4老师 2015-09-22
  • 打赏
  • 举报
回复
闲来无事去读读gcc或g++源代码killtime吧。
赵4老师 2015-09-22
  • 打赏
  • 举报
回复
电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址; 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……
赵4老师 2015-09-22
  • 打赏
  • 举报
回复
盲人摸太阳 说是一物即不中
lm_whales 2015-09-22
  • 打赏
  • 举报
回复
引用 26 楼 lm_whales 的回复:
int a =10; 可以编译为 push eax mov eax,10 mov ebp[a],eax //自动变量 ,全局的话 一般是 mov a,eax .。。。。。 pop eax int a[]={10,9,8,7,6,5,4} : 就 很难 编译为这种代码 可能就成为 (全局数组 ) a dd 10,9,8,7,6 ,5,4 了 也可能编译为(自动数组) a_tmp dd 10,9,8,7,6 ,5,4 了//数据 然后 //代码 push esi push edi push ecx mov esi ,a_tmp lea edi,a[ebp] rep movsd 。。。。 pop ecx pop edi pop esi 常量(表达式),编译成 立即数是很平常的, 变量,某种情况下也可能优化成常量,最终编译成立即数 串字面值 整型,浮点型,数组初始化列表,经常编译成 全局数据 用DB,DW,DD,DF,DQ,TB等伪指令定义 结构,类,可能编译为 结构类型 这一类初始化表,可能用结构定义方式定义 也可能用宏(宏指令)来定义 另外,由于编译器的各种策略,编译选项不同,可以用很多种不同的方法 ,编译同样的C,C++代码
修正一下
learnc2015 2015-09-22
  • 打赏
  • 举报
回复
引用 26 楼 lm_whales 的回复:
int a =10; 可以编译为 mov ebp[a],10 int a[]={10,9,8,7,6,5,4} : 就 很难 编译为这种代码 可能就成为 a dd 10,9,8,7,6 ,5,4 了 也可能编译为 a_tmp dd 10,9,8,7,6 ,5,4 了//数据 然后 //代码 push esi push edi push ecx mov esi ,a_tmp lea edi,a[ebp] rep movsd 常量(表达式),编译成 立即数是很平常的, 变量,某种情况下也可能优化成常量,最终编译成立即数 串字面值 整型,浮点型,数组初始化列表,经常编译成 全局数据 用DB,DW,DD,DF,DQ,TB等伪指令定义 结构,类,可能编译为 结构类型 这一类初始化表,可能用结构定义方式定义 也可能用宏(宏指令)来定义 另外,由于编译器的各种策略,编译选项不同,可以用很多种不同的方法 ,编译同样的C,C++代码
皇上,我是这么理解,初始化必须在内存里赋值才算是初始化 编译的时候赋值不算真正的初始化 我这样理解是否正确?
lm_whales 2015-09-22
  • 打赏
  • 举报
回复
int a =10; 可以编译为 mov ebp[a],10 int a[]={10,9,8,7,6,5,4} : 就 很难 编译为这种代码 可能就成为 a dd 10,9,8,7,6 ,5,4 了 也可能编译为 a_tmp dd 10,9,8,7,6 ,5,4 了//数据 然后 //代码 push esi push edi push ecx mov esi ,a_tmp lea edi,a[ebp] rep movsd 常量(表达式),编译成 立即数是很平常的, 变量,某种情况下也可能优化成常量,最终编译成立即数 串字面值 整型,浮点型,数组初始化列表,经常编译成 全局数据 用DB,DW,DD,DF,DQ,TB等伪指令定义 结构,类,可能编译为 结构类型 这一类初始化表,可能用结构定义方式定义 也可能用宏(宏指令)来定义 另外,由于编译器的各种策略,编译选项不同,可以用很多种不同的方法 ,编译同样的C,C++代码
均陵鼠侠 2015-09-22
  • 打赏
  • 举报
回复
引用 38 楼 worldy 的回复:
[quote=引用 29 楼 zhao4zhong1 的回复:] 盲人摸太阳 说是一物即不中
赵老师开始摸太阳了啊?[/quote] 太阳他辈子怕是摸不着了,朕建议他摸电烙铁,其实也挺烫的。
均陵鼠侠 2015-09-22
  • 打赏
  • 举报
回复
引用 37 楼 worldy 的回复:
[quote=引用 14 楼 sholber 的回复:] [quote=引用 11 楼 zhao4zhong1 的回复:] 编译的时候没初始化,那代码段汇编指令中的常量是谁写上去的?
1,汇编指令中还有常量,这个没听说过; 2,初始化是什么意思,赵老师学C数十载,竟然到现在还没弄明白。 赵老湿以为朕是外国人,不懂中国话吗![/quote] 编译器写的,比如函数体中有 static n=100; n=n++; 编译器会将n放到程序读数据段的某个磁盘单元并且将其值设置为100,exe被加载的时候,整个数据段会原封不动的加载到内存,因此和n对应的存储单元就有100的起始值 [/quote] 首先,你所说的,是业界流行的做法,但流行不代表就是确凿证据。人人都走阳关大道和捷径,但驴友就喜欢走没有路的偏僻丛林,你说不行?如果编译器只在EXE里为n保留一个位置,然后在程序开始执行的时候才用mov指针加一个立即数将100写到n对应的存储单元,难道不行? 其次,初始化这个词本身就没找到完整的定义,讨论起来自然各说各的。就像你说的,整个数据段加载到内存,这个覆盖内存原来东西的操作,不能叫初始化? 最后,n=n++不是一个有确定行为的表达式,赵老师会让你看置顶帖的。
learnc2015 2015-09-22
  • 打赏
  • 举报
回复
引用 24 楼 sholber 的回复:
[quote=引用 22 楼 learnc2015 的回复:] [quote=引用 20 楼 zhao4zhong1 的回复:] 别跟我说被编译器优化为立即数的取值不变的变量不是变量。
看来皇上错了?[/quote] 你要跟老赵辩论问题,认真就输了。他会胡搅蛮缠,没完没了。[/quote] 回皇上,我对赵老师还是很葱白的,赵老师很热心,很愿意帮助别人, 心里是很感激赵老师的 不过皇上的功力也是非凡,也很热心,让我很感动,真皇恩浩荡啊
均陵鼠侠 2015-09-22
  • 打赏
  • 举报
回复
引用 22 楼 learnc2015 的回复:
[quote=引用 20 楼 zhao4zhong1 的回复:] 别跟我说被编译器优化为立即数的取值不变的变量不是变量。
看来皇上错了?[/quote] 你要跟老赵辩论问题,认真就输了。他会胡搅蛮缠,没完没了。
worldy 2015-09-22
  • 打赏
  • 举报
回复
引用 29 楼 zhao4zhong1 的回复:
盲人摸太阳 说是一物即不中
赵老师开始摸太阳了啊?
worldy 2015-09-22
  • 打赏
  • 举报
回复
引用 14 楼 sholber 的回复:
[quote=引用 11 楼 zhao4zhong1 的回复:] 编译的时候没初始化,那代码段汇编指令中的常量是谁写上去的?
1,汇编指令中还有常量,这个没听说过; 2,初始化是什么意思,赵老师学C数十载,竟然到现在还没弄明白。 赵老湿以为朕是外国人,不懂中国话吗![/quote] 编译器写的,比如函数体中有 static n=100; n=n++; 编译器会将n放到程序读数据段的某个磁盘单元并且将其值设置为100,exe被加载的时候,整个数据段会原封不动的加载到内存,因此和n对应的存储单元就有100的起始值
加载更多回复(27)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧