MyException - 我的异常网
当前位置:我的异常网» 操作系统 » C 储存及环境

C 储存及环境

www.MyException.Cn  网友分享于:2013-09-19  浏览:0次
C 存储及环境
    C 程序一般是由下列几部分组成:
    (1)正文段。这是由 CPU 执行的机器指令部分,它通常是可共享的,所以即使是频繁执行的程序(如文本编辑器、C 编译器和 shell 等)在存储器中也只有一个副本。另外,正文段通常是只读的,以防止程序由于意外而修改其指令。
    (2)初始化数据段(简称数据段)。它包含了程序中被明确地赋初值的全局变量等。
    (3)未初始化数据段(也称 bss 段,即“由符号开始的块”(block started by symbol))。函数外的未被初始化声明的变量就被存放在这里。程序开始前,内核将此段中的数据初始化为 0 或空指针。
    (4)栈。自动变量及函数每次调用时所需保存的信息(如返回地址、调用者的环境信息等)都存放在栈中。注意,栈的增长方向一般是从高地址往低地址方向增长的。
    (5)堆。主要用于动态存储分配,一般位于未初始化数据段和栈之间。
    下图是这些段的一种典型存储空间布局。

    从图中可知,未初始化数据段的内容并不存放在磁盘程序文件中,因为内核在程序开始运行前将它们都设置为 0。需要存放在磁盘程序文件中的只有正文段和初始化数据段。
    实际上,编译好的可执行程序中还有若干其他类型的段,如包含符号表的段、包含调试信息的段以及包含动态共享库链接表的段等,不过它们并不装载到进程执行的程序映像中。
    size 命令可报告正文段、数据段和 bss 段的长度(以字节为单位)。如:
$ size /usr/bin/cc /bin/sh
  text    data    bss    dec      hex    filename
346919    3576    6680   357175   57337  /usr/bin/cc
102134    1776    11272  115182   1c1ee  /bin/sh

    其中第 4 列和第 5 列分别是以十进制和十六进制表示的前 3 段的总长度。

    ISO 说明了 3 个用于存储空间动态分配的函数。
#include <stdlib.h>
void *malloc(size_t size);
void *calloc(size_t nobj, size_t size);
void *realloc(void *ptr, size_t newsize);
                      /* 返回值:若成功,都返回非空指针;否则,都返回 NULL */
void free(void *ptr);

    这 3 个函数返回的指针都是适当对齐的,可用于任何数据对象。其中 malloc 分配指定字节数的存储区,其中的初始值不确定;calloc 为指定数量指定长度的对象分配存储空间,其中的每一位都初始化为 0;realloc 可增加或减少以前分配区的长度。当增加长度时,可能需要将以前分配区的内容移到另一个足够大的区域,以便在尾端提供增加的存储区,而新增区域内的初始值则不确定。realloc 的 newsize 参数是存储区的新长度,当 ptr 是空指针时,realloc 的功能就如同 malloc。free 函数可用来释放 ptr 指向的存储空间,以便以后再分配。
    这些分配例程通常用 sbrk 系统调用实现,该系统调用可以扩充或缩小进程的堆。但是大多数 malloc 和 free 的实现都不减小进程的存储空间。释放的空间可供以后再分配,但将它们保持在 malloc 池中而不返回给内核。一般所分配的存储空间都比所要求的要稍大一些,额外的空间会用来记录管理信息,比如分配块的长度、指向下一个分配块的指针等。因此在动态分配的缓冲区前或后进行写操作极有可能会改写另一块的管理记录信息。另外,释放一个已经释放了的块或者释放不是由 alloc 类函数分配的块等都有可能导致致命性的错误。而如果不释放不再使用的空间,则会使进程地址空间长度慢慢增加,直至不再有空闲空间,这被称为泄漏(leakage)。这会导致过度的换页开销,从而造成性能下降。

    每个程序都接收到一张环境表,它是一个字符指针数组,其中每个指针都包含一个指向以 null 结束的 C 字符串的地址,全局变量“extern char **environ”则包含了该指针数组的地址,通常称 environ 为环境指针,指针数组为环境表,其中各指针指向的字符串为环境字符串。例如,一个以 5 个字符串组成的环境看起来大致如下图所示。

    main 函数在大多数 UNIX 系统上的原型是这样的:
        int main(int argc, char **argv[], char *envp[]);
    其中第三个就是环境表地址。不过因为该参数比起 environ 也没有带来多少益处,因此 POSIX.1 也规定应使用 environ 而不使用第 3 个参数。通常用 getenv 和 putenv 等函数来访问和设置特定的环境变量,而不是直接使用 environ,但如果要查看整个环境,则必须使用 environ 指针。
#include <stdlib.h>
char *getenv(const char *name);
                 /* 返回值:指向与 name 关联的 value 的指针;未找到就返回 NULL */
int putenv(char *str);
                 /* 返回值:若成功,返回 0;否则,返回非 0 */
int setenv(const char *name, const char *value, int rewrite);
int unsetenv(const char *name);
                 /* 两个函数返回值:若成功,返回 0;否则,返回 -1 */

    其中:
    * getenv 是用来获取某个环境变量的值。
    * putenv 取形式为“name=value”的字符串,将其放到环境表中。如果 name 已经存在,则先删除其原来的定义。
    * setenv 将 name 设置为 value。如果 name 已经存在,则根据参数 rewrite 的值为 0与否来决定是否覆盖原来的定义。
    * unsetenv 删除 name 的定义,即使不存在也不算出错。
    注意,putenv 和 setenv 的差别在于:putenv 可以自由地将传递给它的参数字符串直接放到环境中(但不应该将存放在栈中的字符串传给它);setenv 必须分配存储空间,以便依据其参数创建 name=value 字符串。
    了解这些函数是如何修改环境表也是非常有益的。其中,环境表和环境字符串通常存放在进程存储空间的顶部(栈之上)。删除一个字符串时只需要在环境表中找到该指针,然后将所有后续指针都向环境表首部顺次移动一个位置。但是增加一个字符串或修改一个现有的字符串就困难得多。因为环境表和环境字符串通常占用的是进程地址空间的顶部,所以它不能再向高地址方向扩展,同时也不能移动在它之下的各栈帧。两者结合使得该空间的长度不能再增加。
    (1)当修改一个现有的 name 时:
    a. 如果新 value 的长度不大于现有的长度,则只要复制新字符串到原字符串所在的空间即可。
    b. 如果新 value 的长度大于原长度,则必须调用 malloc 为新字符串分配空间,然后将新字符串复制到该空间,接着使环境表中的针对 name 的指针指向新分配区。
    (2)当增加一个新的 name 时就复杂多了。必须先调用 malloc 为 name=value 字符串分配空间,然后将该字符串复制到此空间中。
    a. 如果这是第一次增加一个新的 name,则必须调用 malloc 为新的指针表分配空间。接着,将原来的环境表复制到新分配区,并将指向新 name=value 字符串的指针存放在该指针表的表尾,然后又将一个空指针存放在其后。最后使 environ 指向新指针表。如果原来的环境表位于栈顶之上,那么必须将此表移至堆中。但是此表中的大多数指针仍指向栈顶之上的各 name=value 字符串。
    b. 如果这不是第一次增加一个新的 name,则说明之前已在堆中为环境表分配了空间,所以只要调用 relloc,以分配比原空间多存放一个指针的空间,然后将指向新 name=value 的字符串的指针存放在该表表尾,后面跟着一个空指针。

文章评论

程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
我的丈夫是个程序员
我的丈夫是个程序员
 程序员的样子
程序员的样子
程序员和编码员之间的区别
程序员和编码员之间的区别
程序员必看的十大电影
程序员必看的十大电影
老程序员的下场
老程序员的下场
我是如何打败拖延症的
我是如何打败拖延症的
如何成为一名黑客
如何成为一名黑客
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
编程语言是女人
编程语言是女人
那些争议最大的编程观点
那些争议最大的编程观点
一个程序员的时间管理
一个程序员的时间管理
程序员应该关注的一些事儿
程序员应该关注的一些事儿
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
程序员都该阅读的书
程序员都该阅读的书
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
鲜为人知的编程真相
鲜为人知的编程真相
为什么程序员都是夜猫子
为什么程序员都是夜猫子
漫画:程序员的工作
漫画:程序员的工作
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
总结2014中国互联网十大段子
总结2014中国互联网十大段子
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
Java程序员必看电影
Java程序员必看电影
每天工作4小时的程序员
每天工作4小时的程序员
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
程序员的鄙视链
程序员的鄙视链
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
代码女神横空出世
代码女神横空出世
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有