该篇文章作为上一篇文章的补充,重点讲述一下进程的命令行参数,环境变量,以及内存相关的内容。
1. 命令行参数与环境变量
1) 现在 main 函数的形式一般是这样的
int main(int argc, char *argv[])
main函数的参数就叫做命令行参数,这是用户在执行可执行文件时传入的参数。例如用户执行了命令 grep -i hello
那么grep的main函数就会收到参数 argc:3, argv[0] : grep, argv[1] : -i, argv[2] : hello。
总之,argc 表示参数的总数(包括命令本身), argv是参数列表,值得注意的是argv[0] 是命令本身。
2)环境变量
进程是有环境变量的,比如工作目录,根目录,home目录等,我们可以通过一个全局的定义 extern char **environ 来访问所有的环境变量,environ中的每一项都是KEY=VALUE形式的, 比如 environ[1] == "HOME=/home/gengj",下面的代码可以访问到所有的默认环境变量。
#include <stdio.h>
extern char **environ;
int main(int argc, char *argv[])
{
int i = 0;
for (i = 0; environ[i] != NULL; i++) {
printf("%s\n", environ[i]);
}
return 0;
}
除了直接使用environ来访问所有的环境变量,我们也可以使用getenv(char *name) 来获得name指定的环境变量的值,同时我们也可以使用setenv(const char *name, const char *value, int rewrite) 来设置自己的环境变量。
2. 进程的地址空间
Linux中的进程空间是分段的,一个进程的地址空间有以下几个段组成。其中代码段的起始地址为 0x80480000,栈底的地址为0xC0000000。
3. 堆得分配与释放
malloc(size_t size), 在堆上分配大小为size的空间,该空间并没有被初始化,需要用户自己初始化
calloc(size_t nobj, size_t size),在堆上分配size个大小为nobj的空间,也就是总空间为size*nobj,他会将分配的空间初始化为0
realloc(void *ptr, size_t newsize),如果ptr指向的空间后面有足够的空间,他会直接在后面分配额外的空间,否则他会重新分配一个大小为newsize的空间,<span style="font-family: Arial, Helvetica, sans-serif;">然后将ptr指向的内容复制过来,所以返回的指针与ptr并不一定相等。</span>
free(void *ptr), 释放ptr指向的内存空间。
以上三个函数都是使用系统调用sbrk来实现的,sbrk的作用就是扩展堆空间。既然这是一个系统调用,我们可以知道malloc的内存都是从内核申请过来的,不过当这块内存被free的时候,这块内存并不会返还给内核,而是存放在malloc pool中,以便下次malloc的时候直接从pool里面分配。
实际上,malloc的时候,系统实际分配的内存要比申请的size要大一点点,这一点点内存中存放着这块内存的大小以及指向下一个分配过的内存的指针(听起来很像链表呀,没错,系统对堆得管理就是用链表结构来实现的),这一点点内存非常重要,如果你破坏了他你的程序就会有意想不到的运行结果或者直接崩溃, 这就要求我们在编程的时候一定不要越界操作,慎重慎重!!!
4. 栈上的技巧setjmp() 与 longjmp()
首先声明的是,这两个函数是对程序栈的操作,他不会影响在其它段上的数据。
在你想要调到的地方调用 setjmp(), 这个系统调用就会把改点的运行信息保存下来,以便下次你跳回来的时候继续运行;在你想要jump的地方调用longjmp() 这时候你就会跳回到调用setjmp的地方重新运行啦。看下面的代码,longjmp的第二个参数就是setjmp的返回值,jmp_buf 中保存了运行的一些信息,跳转时,在setjmp与longjmp之间的栈空间被释放,中间的一切数据都要从新再生成一遍。
#include <stdio.h>
#include <setjmp.h>
jmp_buf buffer;
void jmp_func()
{
int i = 0;
i++;
printf("%s: i = %d\n", __FUNCTION__, i);
longjmp(buffer, 1);
}
int main()
{
int i_main = 0;
int res = setjmp(buffer);
printf("%s: res = %d\n", __FUNCTION__, res);
i_main++;
printf("%s: i_main = %d\n", __FUNCTION__, i_main);
getchar();
jmp_func();
return 0;
}