一个C程序的内存布局(memory layout)(转)

一个C程序一直以来都是由以下5个段(pieces)组成:

代码段(text segment):存放CPU执行的机器指令(machine instructions)。通常情况下,代码段是可共享的,使其可共享的目的是对于频繁被执行的程序,只需要在内存中有一份拷贝即可,比如文本编辑器(text editors),C编译器,shell等等。另外,代码段也通常是只读的,使其只读的原因是防止一个程序意外地修改了它的指令(prevent a program from accidentally modifying its instructions)。

初始化数据段/数据段(initialized data segment/data segment):该段包含了在程序中明确被初始化的变量。例如,一个不在任何函数内的C声明(C declaration)

int   maxcount = 99;

使得变量maxcount根据其初始值被存储到初始化数据段。

未初始化数据段/bss段(uninitialized data segment/"bss" segment):bss这个叫法是根据一个早期的汇编运算符而来,这个汇编运算符标志着一个块的开始(stood for "block started by symbol")。在程序开始执行之前,bss段的数据被kernel初始化为0或者空指针(null pointers)。一个不在任何函数内的C声明

long sum[1000];

使得变量sum被存储到未初始化数据段/bss段中。

栈段(stack):where automatic variables are stored, along with information that is saved each time a function is called. 每次当一个函数被调用,该函数的返回地址和一些关于caller的信息,比如某些寄存器的内容,将被首先存储到栈段。然后这个被调用的函数(caller)再为它的自动变量和临时变量(automatic and temporary variables)在栈段上分配空间。这就是C如何实现函数的递归调用。每次一个递归函数调用其本身,一个新的栈框架(stack frame)就会被使用,这样这个新实例栈里的一组变量就不会和该函数的另一个实例栈里面的变量互相干扰。

堆段(heap):用于动态内存分配(dynamic memory allocation)。一直以来,堆在内存中的位置是介于bss段和栈段之间。

图7.6显示了这5个段在内存中的典型排列。这是一张逻辑图,表示了一个程序在内存中看起来是怎么样的。对于一个给定的实现,没有强制的要求说必须按照这种方式来排列这5个段。然而,这给了我们一种典型的便于描述的排列方式。运行在Intel x86处理器上的linux,代码段(text segment)从地址0x08048000开始(往上),栈底从地址0xC0000000往下(在这个特定的表示结构中,栈段从高地址向低地址扩展)。在堆顶和栈顶之间的虚拟地址空间是很大的(这保证了2个段不会互相干扰)。

 

在一个a.out中,还有许多段类型存在(Several more segment types exist in an a.out)。如符号表(symbol table),调试信息(debugging information),动态共享库的连接表(linkage tables for dynamic shared libraries)等。这些额外的section(不是segment)不会作为被一个进程执行的程序映象的一部分。

从图7.6中要注意到bss段的内容没有被存储到磁盘上的程序文件中(the program file on disk)。这是因为kernel在程序开始运行之前将该段都置为0。程序中唯一需要被存储到程序文件中的部分是代码段和初始化数据段。

命令size会报告这3个段的大小:代码段,初始化数据段,未初始化数据段。例如:

$ size /usr/bin/cc /bin/sh

       text     data   bss     dec     hex   filename

      79606     1536   916   82058   1408a   /usr/bin/cc

     619234    21120 18260 658614   a0cb6   /bin/sh

第四和第五列是这3个段的总计大小,分别以十进制和十六进制表示出来。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,我可以回答这个问题。以下是用C语言编写的memcpy程序的示例代码: ``` #include <stdio.h> void *my_memcpy(void *dest, const void *src, size_t n) { char *csrc = (char *)src; char *cdest = (char *)dest; for (int i = 0; i < n; i++) { cdest[i] = csrc[i]; } return dest; } int main() { char src[100] = "Hello, world!"; char dest[100]; my_memcpy(dest, src, sizeof(src)); printf("%s", dest); return 0; } ``` 这个程序使用了一个循环来逐个复制源内存中的字节到目标内存中,实现了类似于C语言库函数memcpy的功能。注意,在使用此程序时,需要确保源内存和目标内存的大小都不小于要复制的字节数。 ### 回答2: C语言中提供了一个内置函数memcpy,可以用于实现内存拷贝的功能。下面是一个示例的memory copy程序: ```c #include <stdio.h> #include <string.h> void myMemcpy(void *dest, const void *src, size_t count) { char *csrc = (char *)src; char *cdest = (char *)dest; for (int i = 0; i < count; i++) { cdest[i] = csrc[i]; } } int main() { char str1[] = "Hello, World!"; char str2[20]; myMemcpy(str2, str1, strlen(str1)+1); printf("Copied string: %s\n", str2); return 0; } ``` 上述程序定义了一个myMemcpy函数,接受目标内存起始地址dest、源内存起始地址src和需要拷贝的字节数count作为参数。在函数内部,使用了一个for循环将源内存中的数据逐个拷贝到目标内存中。 在主函数中,我们声明了一个字符数组str1,并给它赋值为"Hello, World!"。然后,我们声明了一个新的字符数组str2,作为目标内存。然后调用myMemcpy函数,将str1中的内容拷贝到str2中。最后,通过printf函数打印出拷贝后的字符串。 这样,我们就实现了一个简单的内存拷贝程序。 ### 回答3: C语言中的memory copy程序是一种用于将源内存区域中的数据复制到目标内存区域的程序。我们可以使用C语言中的memcpy函数来实现此功能。 memcpy函数的原型如下: ```c void* memcpy(void* destination, const void* source, size_t size); ``` 其中,destination表示目标内存区域的起始地址,source表示源内存区域的起始地址,size表示要复制的字节数。 下面是一个使用memcpy函数实现memory copy功能的示例程序: ```c #include <stdio.h> #include <string.h> int main() { char source[20] = "Hello, world!"; char destination[20]; // 使用memcpy函数将source复制到destination memcpy(destination, source, sizeof(source)); printf("源内存区域的数据为:%s\n", source); printf("目标内存区域的数据为:%s\n", destination); return 0; } ``` 在这个示例程序中,我们声明了一个大小为20的源数组source和一个大小为20的目标数组destination。然后,我们使用memcpy函数将source数组中的数据复制到destination数组中。最后,我们分别打印源内存区域和目标内存区域的数据。 通过运行这个程序,我们可以看到源内存区域的数据为"Hello, world!",而目标内存区域的数据也为"Hello, world!",证明memcpy函数成功实现了内存复制的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值