[APUE] 再读之进程环境

本章节讲诉整个进程生命周期的方方面面,包括main 函数,进程终止方式,命令行参数,内存布局,动态库静态库,环境变量以及资源操作。顺带还解释了longjmp,setjmp函数,以及几种变量类型。


1. main 函数

int main(int argc,char* argv[])

main 函数启动时候,从内核取得命令行参数和环境表项。

2. 进程终止方式

五种终止方式: exit(),_exit(), return ,abort, 还有其他信号比如SIGSTOP等等。

exit()执行些IO的清理动作,而_exit()则直接进入内核。如下代码,则可很清楚的看清楚二者之间的区别。

#include 
#include 
#include 

int main(int argc, char* argv[])
{
    printf("Should print if exit() or _exit()\n");
    printf("Should print if exit()");
    //exit(1);
    _exit(1);
}

int atexit(void (*func)(void)) 成功为0,出错非0. 提供程序退出之前注册退出函数的功能,以堆栈方式。先注册的函数,先处理。

#include 
#include 
#include 
#include 


static void f1(void)
{
    printf("In f1 function\n");
}

static void f2(void)
{
    printf("In f2 function\n");
}

int main(int argc, char* argv[])
{
    if(atexit(f1)!=0 || atexit(f2)!=0 || atexit(f2)!=0)
    {
        printf("Register atexit error. errno=%d, reason : %s\n", errno, strerror(errno));
        return 0;
    }
    return 1;
}                                                                                                                                          

3. 命令行参数.两种遍历方式

#include 

int main(int argc, char* argv[])
{

    int i ;
    //for(i=0;i

4. 环境表

环境表存储在进程全局变量 environ 中, 是一个字符串数组,最后一个以NULL结束。所以可以采用如下方式遍历:

#include 

int main(int argc, char* argv[])
{
    extern char** environ;
    int i;
    for(i=0;environ[i]!=NULL;i++)
        printf("%s\n", environ[i]);
}


5. 存储空间

c程序存储空间包含如下几部分:

  • 初始化数据段。 int max =100; 也叫data段。
  • 非初始化数据段。 int min; 也叫bss段。
  • 正文段。正文段共享且只读。也叫text 段。
  • 栈。 自动变量,每次函数调用的信息,返回地址,寄存器信息都存放在栈上。
  • 堆。动态分配的存储空间。

从低地址到高地址空间排列分别为: text段,data段,bss段(由exec设为0),堆段和栈段。


6. 共享库。分为动态链接和静态链接

静态链接,可移植性好,但占用空间也大。下面是linux平台下创建使用静态库的demo.

动态库文件staticlib.c,定义了一个全局变量和一个全局函数。

int global =1;

int f(int x)
{
    return x*x;
}
编译目标文件并压制动态库,这样便得到了 libstaticlib.a 的静态库文件

gcc -c staticlib.c
ar -crv libstaticlib.a staticlib.o

编写main 函数文件,testdota.c ,并链接静态库。

int f(int);
extern int global;
int main(int argc, char* argv[])
{
    printf("result is %d\n, global =%d\n",f(10), global);
}

gcc testdota.c -L ./ -lstaticlib

下面来看下动态库,动态库省空间,运行时候才调用。但移植性不如静态库好。

编写动态库程序dynamic.c

int global =1;

int f(int x)
{
    return x*x*x;
}

testdyn.c

#include 

int f(int);
extern int global;
int main(int argc, char* argv[])
{
    printf("result is %d\n, global =%d\n",f(10), global);
}


生成动态库,并链接。运行的时候可能会遇到找不到.so的问题,可以尝试修改 /etc/ld.so.conf,并运行ldconfig重建cache. 也可以直接把库文件拷贝到/usr/lib

gcc -fPIC -c dynamic.c
gcc -shared -o libdynlib.so dynamic.o
gcc testdyn.c -L ./ -ldynlib


7. 存储器分配函数

malloc, realloc,calloc, free 以及不用操心释放的calloca


8. 环境变量

char* getenv(const char* name);

int putenv(const char* str);

int setenv(const char* name, const char* value, int rewrite);

void unsetenv(const char* name);

操纵环境变量的例子

#include 
#include 

int main(int argc, char* argv[])
{
    extern char** environ;
    int i,res;
    printf("****************Before process enviroment****************\n");
    for(i=0;environ[i]!=NULL;i++)
        printf("%s\n", environ[i]);
    char* homep;
    homep = getenv("HOME");
    printf("home is %s\n", homep);
    res = putenv("TESTENV=a test");
    res = setenv("TESTENV2","a test of env2", 1);
    printf("****************After process enviroment****************\n");
    for(i=0;environ[i]!=NULL;i++)
        printf("%s\n", environ[i]);
    unsetenv("TESTENV");
    printf("****************After unset enviroment****************\n");
    for(i=0;environ[i]!=NULL;i++)
        printf("%s\n", environ[i]);

}

9. jmp相关

setjmp 和longjmp提供跨函数跳转的功能。longjmp跳转后,程序将丢弃原来的调用栈二直接到设置jmp_buf 的位置。

jmp会造成非volatile 变量值的失真。 此段代码能正确显示的是因为定义的变量为全局变量。

#include 
#include 
#include 

jmp_buf buf;
int count =97;
int val = 98;
volatile int sum = 99;
void f();
int main()
{
    printf("count=%d,val =%d, sum=%d\n", count, val,sum);
    if(setjmp(buf)!=0)
        printf("jmp from other place\n");
    else
        f();
    printf("count=%d,val =%d, sum=%d\n", count, val,sum);
}

void f()
{
    printf("in function f\n");
    count++;
    val++;
    sum++;
    longjmp(buf,1);
}


来看下面这段代码, 变量失真了。

#include 
#include 
#include 
jmp_buf buf;
void f();
void g();
int main()
{
    int count =97;
    register int val = 98;
    volatile int sum = 99;
    printf("count=%d,val =%d, sum=%d\n", count, val,sum);
    if(setjmp(buf)!=0)
        printf("count=%d,val =%d, sum=%d\n", count, val,sum);
    else
    {
        count++;
        val++;
        sum++;
        f();
    }
}
void f()
{
    g();
}
void g()
{
    longjmp(buf,1);
}

10.  getrlimit和setrlimit

设置和获得资源的最大值,比如core数量,进程打开文件的句柄数目等等。只有root用户才可以改变硬限制值。

int getrlimit(int source,struct rlimit* ptr)

int setrlimit(int source, const struct rlimit* ptr)

struct rlimit

{

rlim_t rlim_cur;

rlim_t rlim_max;

}

书上的打印各个资源限制的代码:

#include 
#include 
#include 
#define doit(name) pr_limits(#name, name)
static void pr_limits(char*,int);
int main(void)
{
    doit(RLIMIT_CORE);
    doit(RLIMIT_CPU);
    doit(RLIMIT_DATA);
    doit(RLIMIT_FSIZE);
    exit(0);
}

static void pr_limits(char* name, int resource)
{
    struct rlimit limit;
    if(getrlimit(resource,&limit)<0)
    {
        printf("get resource %s error",name );
        return;
    }
    printf("%-14s    ",name);
    if(limit.rlim_cur ==RLIM_INFINITY)
        printf("(infinite)   ");
    else
        printf("%10ld   ", limit.rlim_cur);
    if(limit.rlim_max ==RLIM_INFINITY)
        printf("(infinite)   \n");
    else
        printf("%10ld   \n", limit.rlim_max);

}












你可能感兴趣的:([APUE] 再读之进程环境)