这段C++代码内存是怎么分配的?

软件和网站开发以及相关技术探讨
回复
头像
TheChampionHeart
帖子: 98
注册时间: 2007-10-06 20:49
来自: 中国,天津(Tianjin China)

这段C++代码内存是怎么分配的?

#1

帖子 TheChampionHeart » 2008-11-10 15:37

简化的代码:在程序段内先后声明下面这些变量,就是他们在内存中是怎么存放的弄不懂!
int i = 5;
float f = 2.00;
char str1[] = "Hello";
char str2[10] = "HeyDude";
char *str3 = str1;
const char *str4 = "World";

希望大侠能耐心地详细地解释一下他们在内存中是如何排列的。
我就弄不明白str1的地址怎么和在它上一行定义的float f的地址相差的字节数怎么是 0xbfc33444 - 0xbfc33432
谢谢 :em01

/*******************************
/*******************************/

原代码如下:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string>

using namespace std;

int main(){
int i = 5;
float f = 2.00;
cout << "i = " << i << "; " << "address i = " << &i << endl;
cout << "f = " << f << "; " << "address f = " << &f << endl;
cout << endl;

char str1[] = "Hello"; //!note: the type of str1 is char[6], not char*
cout << "str1 = " << str1 << "; "
<< "address str1 = " << &str1 << "; "
<< *str1 << endl;
cout << "----elements in str1:" << endl;
for(int i = 0; i < 6; i++)
cout << " str[" << i << "] = " << str1 << "; " << endl;
cout << "change 'H' in \"Hello\" with 'W'" << endl;
str1[0] = 'W'; //!note:OK, cos' "Hello\0" which pointed by str1 is not const,
// besides it's stored in STACK
cout << "size of str1 = " << sizeof str1 << endl; //note!: sizeof str1 is the same as "Hello\0"
cout << endl;

char str2[10] = "HeyDude";
cout << "size of str2 is " << sizeof str2 << endl;
cout << endl;

char *str3 = str1;
cout << "str3 = " << str3 << "; "
<< "address str3 = " << &str3 << "; "
<< "the value str3 point to is: " << *str3 << endl;
cout << endl;

const char *str4 = "World"; //!note:the type of str3 is char*
//!error: str4[0] = 'P'; //!note:the string--"World\0" pointed by str3 is stored
// is stored in read-only location
cout << "str4 = " << str4 << "; "
<< "address str4 = " << &str4 << "; "
<< "the value str4 point to is: " << *str4 << endl;
cout << "size of str4 is " << sizeof(str4) << endl; //the size of pointer
return 0;
}

输出如下:
/**************************************
**************************************/
i = 5; address i = 0xbfc33448
f = 2; address f = 0xbfc33444

str1 = Hello; address str1 = 0xbfc33432; H
----elements in str1:
str[0] = H;
str[1] = e;
str[2] = l;
str[3] = l;
str[4] = o;
str[5] =
change 'H' in "Hello" with 'W'
size of str1 = 6

size of str2 is 10

str3 = Wello; address str3 = 0xbfc3343c; the value str3 point to is: W

str4 = World; address str4 = 0xbfc33438; the value str4 point to is: W
size of str4 is 4
头像
wenstream
帖子: 186
注册时间: 2008-06-18 22:02

Re: 这段C++代码内存是怎么分配的?

#2

帖子 wenstream » 2008-11-10 21:36

the memory layout depends on your compiler implement. so when you come across some puzzle, refer to the compiler document
头像
smallqiu@126.com
帖子: 69
注册时间: 2008-10-06 23:03
来自: 青岛

Re: 这段C++代码内存是怎么分配的?

#3

帖子 smallqiu@126.com » 2008-11-10 22:12

那个内存的分配不一定是连续的
这个最好的解释就是 《数据结构》
把你的脸迎向阳光,那就不会有阴影
-----------------------------------------------
头像
TheChampionHeart
帖子: 98
注册时间: 2007-10-06 20:49
来自: 中国,天津(Tianjin China)

Re: 这段C++代码内存是怎么分配的?

#4

帖子 TheChampionHeart » 2008-11-11 10:09

wenstream 写了:the memory layout depends on your compiler implement. so when you come across some puzzle, refer to the compiler document
Thanks, I'm using gcc4.2.4
I'll look into the docs of gcc, but where can I get it? :em01
头像
TheChampionHeart
帖子: 98
注册时间: 2007-10-06 20:49
来自: 中国,天津(Tianjin China)

Re: 这段C++代码内存是怎么分配的?

#5

帖子 TheChampionHeart » 2008-11-11 10:11

smallqiu@126.com 写了:那个内存的分配不一定是连续的
这个最好的解释就是 《数据结构》
能说的在详细一点儿吗?谢谢啦 呵呵
头像
xizhi.zhu
帖子: 46
注册时间: 2008-09-20 4:47
来自: Tampere
联系:

Re: 这段C++代码内存是怎么分配的?

#6

帖子 xizhi.zhu » 2008-11-11 22:31

简单的说,就是所有变量(指针本身也是)的空间都是在栈内分配的,malloc出来的东西在堆上分配的内存,至于常量则看编译器了
头像
BigSnake.NET
帖子: 12522
注册时间: 2006-07-02 11:16
来自: 廣州
联系:

Re: 这段C++代码内存是怎么分配的?

#7

帖子 BigSnake.NET » 2008-11-14 21:16

万恶的对齐?
^_^ ~~~
要理解递归,首先要理解递归。

地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
头像
TheChampionHeart
帖子: 98
注册时间: 2007-10-06 20:49
来自: 中国,天津(Tianjin China)

Re: 这段C++代码内存是怎么分配的?

#8

帖子 TheChampionHeart » 2008-11-15 10:36

BigSnake.NET 写了:万恶的对齐?
字符数组是看作一个整体还是只看作是几个字符--来决定对其方式
头像
TheChampionHeart
帖子: 98
注册时间: 2007-10-06 20:49
来自: 中国,天津(Tianjin China)

Re: 这段C++代码内存是怎么分配的?

#9

帖子 TheChampionHeart » 2008-11-15 10:38

xizhi.zhu 写了:简单的说,就是所有变量(指针本身也是)的空间都是在栈内分配的,malloc出来的东西在堆上分配的内存,至于常量则看编译器了
我就弄不明白str1的地址怎么和在它上一行定义的float f的地址相差的字节数怎么是 0xbfc33444 - 0xbfc33432
希望能解答
头像
wenstream
帖子: 186
注册时间: 2008-06-18 22:02

Re: 这段C++代码内存是怎么分配的?

#10

帖子 wenstream » 2008-11-18 16:54

一般来说,编写C/C++程序并不需要知悉编译器分配内存的细节,如zizhi.zhu所言,了解堆栈(stack),堆(heap)这两者的概念与区别就足够了,除非你是编译器实现者,或者开发嵌入式系统(由于资源相对有限,对内存的使用有苛刻的要求)等其他情况,另当别论,不过如果有兴趣,深入了解多些也好的
在c/c++编译器的设计上,有一个内存数据对齐(也称字节对齐)的原则,用于优化CPU的存取性能,可能会浪费一些内存。lz可以了解一下相关的内容,这里就不详述了

内存的具体布局,基于编译器的实现各异。就字节对齐这一点上,有的编译器优化得好一些,有比较好的算法调整变量间的内存分配布局,有的编译器则相反,浪费的内存会多一些。具体这个编译器的实现就只能参照编译器文档了。
哪里可以弄到这种文档呢,gcc的官网应该有吧。不过我只找到了使用手册,而没有找到实现的描述,又不想掉进“源代码的海”里,如果lz找到实现原则或细节描述的文档,请共享一下。

不过细看上面的程序,lz的问题,我看可以作一个粗浅的解释
str1的地址和在它上一行定义的float f的地址相差的字节数怎么是 0xbfc33444 - 0xbfc33432
从"上一行"这个词来看,lz貌似认为,给出一组相邻定义的变量,编译器肯定会在分配内存时也会严格按定义的次序分配相邻的内存区,事实上,这并非绝对(很多情况都不严格按定义的次序分配内存,不说太远,只考虑上面所说的为字节对齐作的布局优化,分配内存就要进行变量内存区的次序调整),不过一般来说相同类型的变量是相邻存放的
lz的程序我简化如下:

代码: 全选

#include <iostream>
using namespace std;

int main(){
	int i = 5;
	float f = 2.00;
	cout << " i:   address = " << &i << " size "<< sizeof i << endl;
	cout << " f:   address = " << &f << " size "<< sizeof f << endl;

	char str1[] = "Hello"; 
	cout << "str1: address = " << &str1 << " size "<< sizeof str1 << endl;

	char str2[10] = "HeyDude";
	cout << "str2: address = " << &str2 << " size " << sizeof str2 << endl;

	char *str3 = str1;
	cout << "str3: address = " << &str3 << " size "<< sizeof str3 << endl;

	const char *str4 = "World"; 
	cout << "str4: address = " << &str4 << " size " << sizeof str4 << endl;
	
	return 0;
}
我用的是 g++ (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu3)编译,与lz所用的应该是同一个版本的编译器吧,运行情况如下:

代码: 全选

stream@stream:~/program/c.cpp/cpp/workspace$ ./memlayout 
 i:   address = 0xbffd0ca0 size 4
 f:   address = 0xbffd0c9c size 4
str1: address = 0xbffd0c8e size 6
str2: address = 0xbffd0ca6 size 10
str3: address = 0xbffd0c98 size 4
str4: address = 0xbffd0c94 size 4
stream@stream:~/program/c.cpp/cpp/workspace$ 
我们知道堆栈分配有 "从高位到低位" 和 "从低位到高位" 两种方式,从str2与i的地址来看,这里应该是后者。综而观之,这段代码中的变量在内存中的布局应该是这样的:
memlayout.jpg
图中方框中变量后的数字表示此变量所占用的字节大小,如str1占用6个字节,标为6。方框间隔线下方为对应的内存地址值。(图中特别标出变量 i 后面有2个字节,不知道作何用处呢?)
如果单从变量f与str1的地址上看,0xbffd0c9c与0xbffd0c8e中间相差14个字节,无论f与str1都并非14个字节,这段内存是怎么分配的当然就比较令人费解,但是从整个程序的变量内存分配来看,这个内存分配的布局是不难理解的。

上面lz结出的代码与运行结果地址值可以作类似的分析。
头像
TheChampionHeart
帖子: 98
注册时间: 2007-10-06 20:49
来自: 中国,天津(Tianjin China)

Re: 这段C++代码内存是怎么分配的?

#11

帖子 TheChampionHeart » 2008-11-18 23:29

wenstream 写了:一般来说,编写C/C++程序并不需要知悉编译器分配内存的细节,如zizhi.zhu所言,了解堆栈(stack),堆(heap)这两者的概念与区别就足够了,除非你是编译器实现者,或者开发嵌入式系统(由于资源相对有限,对内存的使用有苛刻的要求)等其他情况,另当别论,不过如果有兴趣,深入了解多些也好的
在c/c++编译器的设计上,有一个内存数据对齐(也称字节对齐)的原则,用于优化CPU的存取性能,可能会浪费一些内存。lz可以了解一下相关的内容,这里就不详述了

内存的具体布局,基于编译器的实现各异。就字节对齐这一点上,有的编译器优化得好一些,有比较好的算法调整变量间的内存分配布局,有的编译器则相反,浪费的内存会多一些。具体这个编译器的实现就只能参照编译器文档了。
哪里可以弄到这种文档呢,gcc的官网应该有吧。不过我只找到了使用手册,而没有找到实现的描述,又不想掉进“源代码的海”里,如果lz找到实现原则或细节描述的文档,请共享一下。

不过细看上面的程序,lz的问题,我看可以作一个粗浅的解释
str1的地址和在它上一行定义的float f的地址相差的字节数怎么是 0xbfc33444 - 0xbfc33432
从"上一行"这个词来看,lz貌似认为,给出一组相邻定义的变量,编译器肯定会在分配内存时也会严格按定义的次序分配相邻的内存区,事实上,这并非绝对(很多情况都不严格按定义的次序分配内存,不说太远,只考虑上面所说的为字节对齐作的布局优化,分配内存就要进行变量内存区的次序调整),不过一般来说相同类型的变量是相邻存放的
lz的程序我简化如下:

代码: 全选

#include <iostream>
using namespace std;

int main(){
	int i = 5;
	float f = 2.00;
	cout << " i:   address = " << &i << " size "<< sizeof i << endl;
	cout << " f:   address = " << &f << " size "<< sizeof f << endl;

	char str1[] = "Hello"; 
	cout << "str1: address = " << &str1 << " size "<< sizeof str1 << endl;

	char str2[10] = "HeyDude";
	cout << "str2: address = " << &str2 << " size " << sizeof str2 << endl;

	char *str3 = str1;
	cout << "str3: address = " << &str3 << " size "<< sizeof str3 << endl;

	const char *str4 = "World"; 
	cout << "str4: address = " << &str4 << " size " << sizeof str4 << endl;
	
	return 0;
}
我用的是 g++ (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu3)编译,与lz所用的应该是同一个版本的编译器吧,运行情况如下:

代码: 全选

stream@stream:~/program/c.cpp/cpp/workspace$ ./memlayout 
 i:   address = 0xbffd0ca0 size 4
 f:   address = 0xbffd0c9c size 4
str1: address = 0xbffd0c8e size 6
str2: address = 0xbffd0ca6 size 10
str3: address = 0xbffd0c98 size 4
str4: address = 0xbffd0c94 size 4
stream@stream:~/program/c.cpp/cpp/workspace$ 
我们知道堆栈分配有 "从高位到低位" 和 "从低位到高位" 两种方式,从str2与i的地址来看,这里应该是后者。综而观之,这段代码中的变量在内存中的布局应该是这样的:
memlayout.jpg
图中方框中变量后的数字表示此变量所占用的字节大小,如str1占用6个字节,标为6。方框间隔线下方为对应的内存地址值。(图中特别标出变量 i 后面有2个字节,不知道作何用处呢?)
如果单从变量f与str1的地址上看,0xbffd0c9c与0xbffd0c8e中间相差14个字节,无论f与str1都并非14个字节,这段内存是怎么分配的当然就比较令人费解,但是从整个程序的变量内存分配来看,这个内存分配的布局是不难理解的。

上面lz结出的代码与运行结果地址值可以作类似的分析。
谢谢wenstream了,这些变量在内存里面排放的位置应该是在编译是就确定的吧?没有顺序排放应该是编译器的原因?
我再找找...... 还有那个2 很诡异
头像
command
帖子: 306
注册时间: 2007-10-14 0:50
来自: GUCAS

Re: 这段C++代码内存是怎么分配的?

#12

帖子 command » 2008-11-19 0:42

用objdump查看一下反汇编的结果,不就什么都清楚了!这与编译器有关的。
OS: Debian GNU/Linux
Version: lenny
Kernel: 2.6.36
Xorg: 1.4.2
CPU: Intel(R) Core(TM)2 Duo CPU E8400 @ 3.00GHz
HD: 320G SATA
Memory: 2G DDRIII
Graphics:Mobility Radeon HD 3450
头像
Final_x
帖子: 383
注册时间: 2008-05-03 23:05
联系:

Re: 这段C++代码内存是怎么分配的?

#13

帖子 Final_x » 2008-11-20 14:29

:em11 wenstream
回复