APUE笔记-进程环境

进程环境

进程的内核空间映射到同一块物理地址。进程只能读写用户空间。用户空间映射到不同的物理地址,进程只能读写自己的用户空间。

PCB在内核空间,操作系统按照页管理内存。

每个页可以设置读写访问权限。参考MMU的设置代码。

Linux只用了两个特权级别。(Intel的CPU 4个特权级)

 

ISO C规定一个进程可以登记最多32个函数,这些函数由exit自动调用

atexit(stdlib.h)函数用来登记这些函数:调用顺序和登记顺序相反,同一函数登记多次也会调用多次。

环境表

每个程序都接收到一张环境表。环境表是字符指针数组。

extern char **environ;这个全局变量包含该指针数组的地址。

大多数UNIX系统支持main函数的第三个参数,就是char*envp[]环境表的地址。
POSIX.1规定使用environ而不使用第三个参数。ISO规定main函数由两个参数。

size命令报告程序的存储空间各个段的长度。

共享库

gcc -static hello.c   阻止gcc使用共享库

gcc hello.c              gcc默认使用共享库

共享库的编译方法:

先创建共享库源文件add.c

  1 int add(int a,int b)                                                                                                                              
  2 {
  3     return a+b;
  4 }

编译

gcc add.c -fPIC -shared -o libadd.so
-fPIC   生成位置无关代码
-shared 生成共享库

编写测试文件main.c

  1 #include                                                                                                                                 
  2 
  3 int add(int,int);
  4 
  5 int main()
  6 {
  7     printf("%d\n",add(1,2));
  8 }

编译

gcc main.c -L /home/myhome/apue/libso/ -ladd -o main.o
-L 指明共享库的路径
-ladd  指明共享库的名称

执行以下操作

cd /etc/ld.so.conf.d/
创建文件usr-libs.conf
vim usr-libs.conf 
写入/home/myhome/apue/libso  
sudo ldconfig

存储空间分配

alloca在当前函数的栈帧上分配空间,不是在堆上,因此不必关心释放问题。有些系统函数已被调用后不能增加栈帧长度,也就不支持alloca。书中讨论的四个平台都提供这个函数。

环境变量

#include

char * getenv(const char * name)返回指针指向name=value中的value。

应当使用这个函数,而不是直接访问environ。

int putenv(char *str)参数为name=value,如果已存在,删除原来的

setenv

unsetenv

环境表在进程地址空间的顶部,不能向上增长,也不能向下增长。

如果更改的value长度大于原来的value,则malloc为新的字符串分配空间,将环境表中针对name的指针指向新的空间。

增加新的name,malloc分配新的空间,把环境表复制到新的空间,name=value的指针放到环境表的尾部,再将空指针放在其后,原来的指针不变。environ指向新的环境表。环境表原来在栈顶之上,现在移动到堆上。

跨越函数的跳转

C语言中,goto不能跨函数跳转。

setjmp和longjmp可以。

#include 

实验:longjmp之后,各种类型的变量的变化

    1 #include                                                                                                                               
    2 #include "apue.h"
    3 #include 
    4 
    5 static void f1(int ,int ,int ,int);
    6 static void f2(void);
    7 
    8 static jmp_buf jmpbuffer;
    9 static int global;
   10 
   11 int main()
   12 {
   13     int autoval;
   14     register int regval;
   15     volatile int volaval;
   16     static int staval;
   17     global = 1;
   18     autoval = 2;
   19     regval = 3;
   20     volaval  =4;
   21     staval = 5;
   22 
   23     if(setjmp(jmpbuffer)!=0)
   24     {
   25         printf("global=%d,autoval=%d,regval=%d,volaval=%d,staval=%d\n",global,autoval,regval,volaval,staval);
   26         exit(0);
   27     }
   28 
   29     global = 100;
   30     autoval = 200;
   31     regval = 300;
   32     volaval  =400;
   33     staval = 500;
   34     f1(autoval,regval,volaval,staval);
   35     exit(0);
   36 
   37 }
   38 
   39 static void f2()
   40 {
   41     longjmp(jmpbuffer,1);
   42 }
   43 static void f1(int a,int b,int c,int d)
   44 {
   45     printf("in f1():\n");
   46     printf("global=%d,autoval=%d,regval=%d,volaval=%d,staval=%d\n",global,a,b,c,d);
   47     f2();
   48 
   49 }
   50  

运行结果

未优化

in f1():
global=100,autoval=200,regval=300,volaval=400,staval=500
global=100,autoval=200,regval=300,volaval=400,staval=500

用-O选项优化之后

in f1():
global=100,autoval=200,regval=300,volaval=400,staval=500
global=100,autoval=2,regval=3,volaval=400,staval=500

解释:存储器中的变量在longjmp之后,值为最近呈现的值,CPU和浮点寄存器中的变量将恢复为调用setjmp的值。

关于volatile的理解:自动变量和寄存器变量经过优化之后,会放到寄存器中(P174),volatile变量仍然在存储器中。

如果要编写非局部跳转的程序,最好用volatile。

资源限制

getrlimit

setrlimit

  1 #include                                                                                                                                 
  2 #include "apue.h"
  3 #include 
  4 
  5 int main()
  6 {
  7     struct rlimit limit;
  8     getrlimit(RLIMIT_CORE,&limit);
  9     printf("rlimit_cur=%lu\n",(unsigned long)limit.rlim_cur);
 10     printf("rlimit_max=%lu\n",(unsigned long)limit.rlim_max);
 11 }

运行结果

rlimit_cur=0
rlimit_max=18446744073709551615

 

你可能感兴趣的:(C语言,UNIX环境高级编程)