关于const常量的存储位置

patricxuqi 2010-06-01 10:30:17
网上有说const常量存储于符号表里。于是做了下实验,但是实验结果好像并不完全是。个人认为应该这样说:符号表里存放的内容包括类中的静态常量和全局变量。不知这个断言对吗?以下是实验代码和结果。大家有什么看法?欢迎拍砖。
#include <iostream>
using namespace std;

const int i = 100;
int n = 0;

class CTest
{
public:
CTest():j(0),l(0){};
int l;
const int j;//静态成员变量必须由默认构造函数初始化
static const int k = 102;
};

void main()
{
CTest ct ;
int m = 0;
const int o = 0;

long addri = (long)&i;
long addrl = (long)&ct.l;
long addrj = (long)&ct.j;
long addrk = (long)&ct.k;
long addrm = (long)&m;
long addrn = (long)&n;
long addro = (long)&o;

cout<<"addr i="<<addri<<endl; //addr i=4290560(符号表)
cout<<"addr l="<<addrl<<endl; //addr l=1310556
cout<<"addr j="<<addrj<<endl; //addr j=1310560
cout<<"addr k="<<addrk<<endl; //addr k=4290564(符号表)
cout<<"addr m="<<addrm<<endl; //addr m=1310544
cout<<"addr n="<<addrn<<endl; //addr n=4297032(符号表)
cout<<"addr o="<<addro<<endl; //addr o=1310532
getchar();
}
...全文
4484 29 打赏 收藏 转发到动态 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
nazzon2004 2010-09-08
  • 打赏
  • 举报
回复
常量的地址。
const 初始化多少 就是那个整形数的地址
leavestarshining 2010-09-07
  • 打赏
  • 举报
回复
c++里的常量折叠(或者常量替换)是将const常量放在符号表中,而并不给其分配内存。编译器直接进行替换优化。
开始理解了...
tian_jut 2010-07-06
  • 打赏
  • 举报
回复
另外建议参看此文
你的变量究竟存储在什么地方 && 全局内存
tian_jut 2010-07-06
  • 打赏
  • 举报
回复 1
const全局变量存放在.rodata只读数据段里,修改会造成SEGV
const局部变量存放在栈上,和普通局部变量无差别,可以用指针间接修改const值。

理由:
在linux上验证。
const int data = 1; //使用指针修改引起程序SEGV崩溃
main()
{
int *p = &data;
*p = 2;

}

编译完后使用objdump -t或者readelf -s命令,可以发现data被放在.rodata section

说放在符号表是不对的。
rabbitgoat 2010-06-02
  • 打赏
  • 举报
回复
我是来学习的,同意楼上的建议,常量折叠
CVA4508M 2010-06-02
  • 打赏
  • 举报
回复
google了下

呵呵,原来 "常量折叠"也就是来自C++的编程思想。。
我直接看英文版的,倒是第一次见这个名词。。

http://hi.baidu.com/american%CC%F0%B3%C8/blog/item/345d36507bc88a2d43a75b3e.html
CVA4508M 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 cva4508m 的回复:]
引用楼主 patricxuqi 的回复:
网上有说const常量存储于符号表里。于是做了下实验,但是实验结果好像并不完全是。个人认为应该这样说:符号表里存放的内容包括类中的静态常量和全局变量。不知这个断言对吗?以下是实验代码和结果。大家有什么看法?欢迎拍砖。

C/C++ code
#include <iostream>
using namespace std;

const int……
[/Quote]

之前说了,符号表是编译器里的东西
实验的话,只能看编译器的源码了。。。。
本人就没研究过了,楼主有兴趣的话,可以翻翻编译器的源码,看看里面是否有这样的优化
CVA4508M 2010-06-02
  • 打赏
  • 举报
回复
C++编程思想真是一本非常好的书,最近在CSDN上看到好多问题
都可以在里面找到答案。
推荐大家都好好看看
CVA4508M 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用楼主 patricxuqi 的回复:]
网上有说const常量存储于符号表里。于是做了下实验,但是实验结果好像并不完全是。个人认为应该这样说:符号表里存放的内容包括类中的静态常量和全局变量。不知这个断言对吗?以下是实验代码和结果。大家有什么看法?欢迎拍砖。

C/C++ code
#include <iostream>
using namespace std;

const int i = 100;
int n = 0;
……
[/Quote]
const常量存储于符号表里,这是编译器的一个优化而已
现在的编译器很聪明的,当你没有对const变量进行&运算的时候,它就可能做这个优化

另外,发现楼主对符号表的理解错了,
符号表,仅仅是在编译器编译时,在编译器编译过程中编译器内部产生的一个临时的列表而已。
编译结束后就不再需要的。所以,它是不会占用程序的内存

cout<<"addr i="<<addri<<endl; //addr i=4290560(符号表)

这里的4290560不过是一个一般的内存地址而已
(由于楼主对const做了取值,所以聪明的编译器取消了这个优化)


引用《C++编程思想》中的一段

C++中的const默认为内部连接,也就是说,const仅在const被定义过的文件里才是可见的,而在连接时不能被其他编译单元看到。当定义一个const时,必须赋一个值给它,除非用extern作出了清楚的说明。
通常C++编译器并不为const创建存储空间,相反它把这个定义保存在它的符号表里。但是extern强制进行了存储空间分配(另外还有一些情况,如取一个const的地址,也要进行存储空间分配),由于extern意味着使用外部连接,因此必须分配存储空间,这也就是说有几个不同的编译单元应当能够引用它,所以它必须存储空间。





pengzhixi 2010-06-02
  • 打赏
  • 举报
回复
这就是所谓的常量折叠,你可以去google常量折叠,或许有解释得更清楚的。
pengzhixi 2010-06-02
  • 打赏
  • 举报
回复
const int i=10;//这个类似宏替换,也就是说,它优化之后可能是放一个符号表里面。所有使用i的地方都用10代替,但是当你对i取址后,没办法,编译器必须为i在常量区找个地方安身。
patricxuqi 2010-06-02
  • 打赏
  • 举报
回复
越来越困惑。期待高手用“实验”来证明!
CVA4508M 2010-06-02
  • 打赏
  • 举报
回复
建议楼主复习下编译原理吧。。。
CVA4508M 2010-06-02
  • 打赏
  • 举报
回复

另外,发现楼主对符号表的理解错了,
符号表,仅仅是在编译器编译时,在编译器编译过程中编译器内部产生的一个临时的列表而已。
编译结束后就不再需要的。所以,它是不会占用程序的内存


楼主仍然没理解符号表。。。
你说的那个能导出的符合表。。是目标文件中,用于连接的那个符号表,跟我们说的,编译器优化使用的符号表,是两个完全不同的东西。。。
patricxuqi 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 cva4508m 的回复:]
引用楼主 patricxuqi 的回复:
网上有说const常量存储于符号表里。于是做了下实验,但是实验结果好像并不完全是。个人认为应该这样说:符号表里存放的内容包括类中的静态常量和全局变量。不知这个断言对吗?以下是实验代码和结果。大家有什么看法?欢迎拍砖。

C/C++ code
#include <iostream>
using namespace std;

const int……
[/Quote]
持保留意见
patricxuqi 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 pengzhixi 的回复:]
你想看编译后的PE文件内容?
[/Quote]
是想知道。看看到底放了些什么东西在里面。linux下可以导出符号表里面的东西。但是不知道windows下面怎么弄。我另开一贴吧。
CVA4508M辛苦了。
CVA4508M 2010-06-02
  • 打赏
  • 举报
回复
$ uname -r
2.6.32-22-generic
$ g++ --version
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ cat main.cpp
#include <iostream>

using namespace std;

int main()
{
const int a = 1;
const int b = 2;
int sum = a + b;
cout << sum;
return 0;
}
$ g++ main.cpp -o test-release
$ g++ -O3 main.cpp -o test-o3

test-o3

public main
main proc near
push ebp
mov ebp, esp
and esp, 0FFFFFFF0h
sub esp, 10h
mov dword ptr [esp+4], 3
mov dword ptr [esp], offset _ZSt4cout@@GLIBCXX_3_4
call __ZNSolsEi ; std::ostream::operator<<(int)
xor eax, eax
leave
retn
main endp



test-release

public main
main proc near
push ebp
mov ebp, esp
and esp, 0FFFFFFF0h
sub esp, 20h
mov dword ptr [esp+1Ch], 1
mov dword ptr [esp+18h], 2
mov dword ptr [esp+14h], 3
mov eax, [esp+14h]
mov [esp+4], eax
mov dword ptr [esp], offset _ZSt4cout@@GLIBCXX_3_4
call __ZNSolsEi ; std::ostream::operator<<(int)
mov eax, 0
leave
retn
main endp


楼主自己看吧,不说了
赵4老师 2010-06-02
  • 打赏
  • 举报
回复
VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!

无汇编无真相!
pengzhixi 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 patricxuqi 的回复:]
在linux系统下,const存放在rdata里面。windows下怎么看数据段呢?
[/Quote]
你想看编译后的PE文件内容?
patricxuqi 2010-06-02
  • 打赏
  • 举报
回复
在linux系统下,const存放在rdata里面。windows下怎么看数据段呢?
加载更多回复(9)

64,318

社区成员

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

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