天天看点

Linux的进程环境

一、命令行参数

当执行一个程序时,调用exec的进程可将命令行参数传递给该新程序。注意:通常echo(1)程序不回显第0个程序。

【例】将所有命令行参数回显到标准输出

Linux的进程环境

注:ISO和POSIX.1都要求argv[argc]是一个空指针。这就使得我们可以将参数处理循环改写为:for(i = 0; argv[i] != NULL; i++)。其中,argc是命令行参数的数目,argv是指向参数的各个指针所构成的数组。

二、环境表

每个程序都接收到一张环境表。与参数表一样,环境表也是一个字符指针数组,其中每个指针包含一个以null结束的C字符串的地址。全局变量environ则包含了该指针数组的地址:extern char **environ。

【例】如果该环境包含5个字符串,那么它看起来如下图所示:

Linux的进程环境

释:

1)每个字符串的结尾处都显示的有一个null字节。

2)environ为环境指针(environment pointer),指针数组为环境表,其中各指针指向的字符串为环境字符串。

3)用getenv和putenv函数来访问特定的环境变量,而不是用environ变量。但是,如果要查看整个环境,则必须用environ指针。

三、C程序的存储空间分布

其组成在空间中的分布,如下图所示:

Linux的进程环境

1、正文段:由CPU执行的机器指令部分,是共享的、只可读的。

2、初始化数据段:通常此段称为数据段,它包含了程序中需明确赋初值的变量。

3、未初始化数据段:通常此段称为bss段,在程序开始执行之前,内核将此段中的数据初始化为0或空指针。

4、栈:

(1)自动变量以及每次函数调用时所需保存的信息都保存在此段中。

(2)每次函数函数调用时,其返回地址及调用者的环境信息。

注意:每次递归函数调用自身时,就用一个新的栈帧,因此一次函数调用实例中的变量集不会影响另一次函数调用中的实例。

5、堆:位于未初始化数据段和栈之间,堆顶和栈顶之间的。程序通常在堆中进行动态分配。

6、注意:

(1)未初始化数据段的内容并不存放在磁盘文件程序中,其原因是:内核在程序开始运行前将他们都设置为0,需要存放在磁盘文件中的段只有正文段和初始化数据 段。

(2)a.out中还有若干其他类型的段,如

1)符号表的段;

2)调试信息的段;

3)动态共享库链接表的段

7、计算各段的长度

【例】Size命令计算正文段、数据段和bss段的长度(以字节为单位)。

Linux的进程环境

释:第四列和第五列分别表示十进制和十六进制表示的3段总长度。

四、共享库

1、使用说明

共享库使得可执行文件中不再需要包含公用的库函数,而只需在所有进程都可引用的存储区中保存这种库例程的一个副本。

2、使用共享库的优点

(1)程序第一次执行或者第一次调用某个库函数时,用动态链接方法将程序与共享库函数相连接,可减少每个执行文件的长度,但是会增加运行时间的开销。这种时间的开销发生在该程序第一次被执行时,或者共享库函数第一次被调用时。

(2)可以用库函数的新版本代替旧版本而无需对使用该库的程序重新连接编辑(假定参数的类型和数目都没有发生变化)。

五、环境变量

1、基本概念:

(1)含义:一般指在操作系统中用来指定操作系统运行环境的一些参数。如:我们编写C/C++代码,在连接的时候从来不知道所链接的动、静态库在哪里,但是照样可以链接成功,生成可执行程序。原因是:有关环境变量帮助编译器进行查找。

(2)性质:具有全局特性。

2、常用环境变量

(1)PATH*:指定命令的搜索路径。

(2)HOME*:指定用户的主工作目录,即用户登录到Linux系统中时默认的目录。

(3)HISTSIZE*:指保存历史命令记录的条数。

(4)SHELL*:当前Shell,它的值通常是/bin/bash。

3、查看PATH

echo $NAME//NAME指环境变量名

【例】

Linux的进程环境

4、测试环境变量

(1)测试PATH

(2)测试HOME

(3)测试HISTSIZE

5、和环境变量相关的命令

(1)echo:显示某个环境变量值。

(2)export:设置一个新的环境变量。

(3)env:显示所有的环境变量。

(4)set:显示本地定义的Shell变量和环境变量。

6、通过代码获取环境变量

【例1】获取命令行的第三个参数

[hongji@localhost ]$ cat -n argv1.c
       #include<stdio.h>
       #include<stdlib.h>
       
       int main(int argc, char *argv[], char *env[])
       {
           int i = ;
           for(; env[i]; i++){
               printf("%s\n", env[i]);
           }
          return ;
      }
           

运行结果:

Linux的进程环境

【例2】通过第三方变量environ获取

[[email protected] _23]$ cat -n environ1.c 
       #include<stdio.h>
       #include<stdlib.h>
       
       int main(int argc, char *argv[])
       {   
           extern char **environ;
           int i = ;
           for(; environ[i]; i++){
               printf("%s\n", environ[i]);
          }
          return ;
      }   
           

运行结果:

Linux的进程环境

释:libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明。

【例3】通过系统调用获取或设置环境变量

[hongji@localhost ]$ cat -n getenv1.c 
       #include<stdio.h>
       #include<stdlib.h>
       
       int main()
       {
           printf("%s\n", getenv("PATH"));
           return ;
       }
           

运行结果:

Linux的进程环境

【例4】环境变量具有全局属性,可以被子进程继承下去

Linux的进程环境

分析:

1)直接查看,发现没有结果,说明该环境变量根据不存在。

2)如果导出环境变量:export MYENV=”hello world”,再次运行程序,发现结果有了。说明:环境变量是可以继承下去的。

3)如果只进行MYENV=”hello world”,不调用export导出,再用进程查看会有什么结果?结果如下图所示:

释:因为不调用export,能到的只是普通变量。

继续阅读