关于const的问题

delphiwcdj 2010-10-13 04:27:25
在一本书上看到下面的讲解,然后在VS2008下调试了一下,发现在const int N=100;这条语句时,有内存分配发生,并不是作者所说的那样,请问这是与编译器相关的吗?

#include <cstdio>
#define M 3// 宏常量

int main()
{
const int N=100;// 此时并未将N放入内存中
NULL;
int a=N;// 此时为N分配内存,以后不再分配
NULL;
int b=M;// 预编译期间进行宏替换,分配内存
NULL;
int c=N;// 没有内存分配
NULL;
int d=M;// 再进行宏替换,又一次分配内存

return 0;
}

汇编代码如下:

#include <cstdio>
#define M 3// 宏常量

int main()
{
0042D600 push ebp
0042D601 mov ebp,esp
0042D603 sub esp,0FCh
0042D609 push ebx
0042D60A push esi
0042D60B push edi
0042D60C lea edi,[ebp-0FCh]
0042D612 mov ecx,3Fh
0042D617 mov eax,0CCCCCCCCh
0042D61C rep stos dword ptr es:[edi]
const int N=100;// 此时并未将N放入内存中
0042D61E mov dword ptr [N],64h
NULL;
int a=N;// 此时为N分配内存,以后不再分配
0042D625 mov dword ptr [a],64h
NULL;
int b=M;// 预编译期间进行宏替换,分配内存
0042D62C mov dword ptr [b],3
NULL;
int c=N;// 没有内存分配
0042D633 mov dword ptr [c],64h
NULL;
int d=M;// 再进行宏替换,又一次分配内存
0042D63A mov dword ptr [d],3

return 0;
0042D641 xor eax,eax
}
0042D643 pop edi
0042D644 pop esi
0042D645 pop ebx
0042D646 mov esp,ebp
0042D648 pop ebp
0042D649 ret


谢谢!
...全文
354 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
delphiwcdj 2010-10-18
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 freezezdj 的回复:]

引用 21 楼 delphiwcdj 的回复:

引用 7 楼 taodm 的回复:

呃,楼主在debug模式下折腾这东西,有点搞笑的味道在里面了。

您的意思是在D模式下代码没有进行优化,所以讨论这个没有意义吗。那该如何测试呢?


Debug 下,编译器会保存大量运行时不需要的数据,用于调试信息。所以和真正的release版的汇编不同。
所以有时候我们在Debug下没问……
[/Quote]
呵呵,谢谢你了!以后多向你们学习……
冻结 2010-10-18
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 delphiwcdj 的回复:]

引用 7 楼 taodm 的回复:

呃,楼主在debug模式下折腾这东西,有点搞笑的味道在里面了。

您的意思是在D模式下代码没有进行优化,所以讨论这个没有意义吗。那该如何测试呢?
[/Quote]

Debug 下,编译器会保存大量运行时不需要的数据,用于调试信息。所以和真正的release版的汇编不同。
所以有时候我们在Debug下没问题的代码,在release下就不行。
另外,taodm的每句话都需要细细体味的。
delphiwcdj 2010-10-14
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 taodm 的回复:]

呃,楼主在debug模式下折腾这东西,有点搞笑的味道在里面了。
[/Quote]
您的意思是在D模式下代码没有进行优化,所以讨论这个没有意义吗。那该如何测试呢?
delphiwcdj 2010-10-14
  • 打赏
  • 举报
回复
我只是想验证一下作者的提法是否正确,并无其他意思。
下面摘自原文:
const定义的只读变量从汇编的角度来看,只是给出了对应的内存地址(好像不是这样,VS下全局和局部的时候都是用立即数直接赋值的,并没有出现内存地址呀),而不是像#define一样给出的是立即数,所以,const定义的只读变量在程序运行过程中只有一份拷贝,而#define定义的宏常量在内存中有若干个拷贝。#define宏是在预编译阶段进行替换,而const修饰的只读变量是在编译的时候确定其值。#define宏没有类型,而const修饰的只读变量具有特定的类型。
delphiwcdj 2010-10-14
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 bichenggui 的回复:]

哎,有些书真是害人不浅。
楼主如果懂汇编的话,就知道了
0042D61E mov dword ptr [N],64h
这句汇编表明N已经在内存里分配了。

如果const是全局常量的话,一般的编译器会将其当作编译期常量,(预处理)编译时的时候就全部被直接用其值替换了。
[/Quote]
谢谢17和18L!
书上的作者在谈到const的特点时,提到了一个优点:“节省空间,避免不必要的内存分配,同时提高效率”。
我的疑问是:
当const变量是全局的时候,VS编译器没有为其分配存储空间,即像17L所言,把当做立即数进行替换。
但是,当声明const变量为局部变量的时候,VS编译器是为其分配了空间的。这样的话,所提的const的这个“优点”是不是特指的全局变量的时候呢。
必成桂 2010-10-13
  • 打赏
  • 举报
回复
哎,有些书真是害人不浅。
楼主如果懂汇编的话,就知道了
0042D61E mov dword ptr [N],64h
这句汇编表明N已经在内存里分配了。

如果const是全局常量的话,一般的编译器会将其当作编译期常量,(预处理)编译时的时候就全部被直接用其值替换了。
arong1234 2010-10-13
  • 打赏
  • 举报
回复
尽信书则不如无书,直观的理解看,你这个int a=N没有任何理由要求N有存储空间,在编译期间把N的值直接替换成立即数没有任何问题。我怀疑要么书写错了,要么你没理解书

在我看来,任何试图获得常量地址的行为都是不合理的。既然是常量,你就不可能去修改它,你取他地址又什么用[Quote=引用 14 楼 delphiwcdj 的回复:]
调试代码为:

C/C++ code

#include <cstdio>
#define M 3// 宏常量
const int N=100;// 此时并未将N放入内存中
int g_val=1;

int main()
{
//const int N=100;// 此时并未将N放入内存中

int a=N;// 此时为N分配内存,以后不再分配

……
[/Quote]
delphiwcdj 2010-10-13
  • 打赏
  • 举报
回复
还有一个问题:
const变量分别作为全局变量和局部变量,分别存储在内存的什么位置?和const修饰符有关系吗?
高手勿笑 :)
delphiwcdj 2010-10-13
  • 打赏
  • 举报
回复
调试代码为:

#include <cstdio>
#define M 3// 宏常量
const int N=100;// 此时并未将N放入内存中
int g_val=1;

int main()
{
//const int N=100;// 此时并未将N放入内存中

int a=N;// 此时为N分配内存,以后不再分配

int b=M;// 预编译期间进行宏替换,分配内存

int c=N;// 没有内存分配

int d=M;// 再进行宏替换,又一次分配内存

return 0;
}

调试中间结果显示:

问题是:
书上的作者说:在语句,int a=N;// 此时为N分配内存,以后不再分配
但是从调试结果上看,const变量N始终没有分配内存。是自己理解有误还是书上说法不对呢?

请高手指点!
xjh53759299 2010-10-13
  • 打赏
  • 举报
回复
是楼主没看懂汇编CONST是编译是的常量,已经直接用数值替换了
int a=N;// 此时为N分配内存,以后不再分配
0042D625 mov dword ptr [a],64h
NULL;
int b=M;// M直接用3替了
0042D62C mov dword ptr [b],3
NULL;
int c=N;// N直接用100替了(64h=100)
0042D633 mov dword ptr [c],64h
NULL;
int d=M;// M直接用3替了
0042D63A mov dword ptr [d],3
Rainqin123 2010-10-13
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 taodm 的回复:]
呃,楼主在debug模式下折腾这东西,有点搞笑的味道在里面了。
[/Quote]

多赐教....
delphiwcdj 2010-10-13
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 gules 的回复:]

LZ,你试试将const int N = 100;放到main()函数之外,再看看汇编是不是有所变化呢!
同时,0042D625 mov dword ptr [a],64h 这一句不正是直接用100来替换N的吗?

另外,作者对于const与define的比较说明实在不敢苟同,怎么会扯到内存分配、提高效率这个上面来呢?建议别再看这样的书了!
实际上一般我们说用const替换define……
[/Quote]
放在main外面,是作者说的情况,谢谢!
gules 2010-10-13
  • 打赏
  • 举报
回复
LZ,你试试将const int N = 100;放到main()函数之外,再看看汇编是不是有所变化呢!
同时,0042D625 mov dword ptr [a],64h 这一句不正是直接用100来替换N的吗?

另外,作者对于const与define的比较说明实在不敢苟同,怎么会扯到内存分配、提高效率这个上面来呢?建议别再看这样的书了!
实际上一般我们说用const替换define的真正含义是“用编译器来替换预处理器,以解决强数据类型的要求”,也就是说用编译器来检查数据类型是否匹配,以避免预处理器因数据类型问题而带来的副作用。
delphiwcdj 2010-10-13
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 taodm 的回复:]

呃,楼主在debug模式下折腾这东西,有点搞笑的味道在里面了。
[/Quote]
请您指点!:)
delphiwcdj 2010-10-13
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 pengzhixi 的回复:]

首先你汇编语句都对应错误了。
[/Quote]
这是直接在编译器下粘过来的代码怎么会有错呢。
taodm 2010-10-13
  • 打赏
  • 举报
回复
呃,楼主在debug模式下折腾这东西,有点搞笑的味道在里面了。
pengzhixi 2010-10-13
  • 打赏
  • 举报
回复
首先你汇编语句都对应错误了。
delphiwcdj 2010-10-13
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 freezezdj 的回复:]

const int N = 100;

分配不分配看编译器实现者的心情。
一般要取N的地址时,可能必须要分配内存了。


“常量折叠”
[/Quote]
谢谢,如果VS是这样实现的,好像就不存在作者所说的,“这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。”
delphiwcdj 2010-10-13
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 healer_kx 的回复:]

哪句汇编对应哪句代码,楼主你开玩笑呢.
[/Quote]
const int N=100;// 此时并未将N放入内存中
0042D61E mov dword ptr [N],64h
delphiwcdj 2010-10-13
  • 打赏
  • 举报
回复
作者在讲解const与define的对比时,提到了const的一个特点是:节省空间,避免不必要的内存分配,同时提高效率。作者指出,编译器通常不为普通const只读变量分配内存存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。然后就举了上面的例子。
作者的意思是:const变量在内存中只有一份拷贝;而宏定义可能存在若干个拷贝。

加载更多回复(2)

64,681

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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