7.2main函数
c程序总是从main函数开始执行。main函数的原型:
int main(int argc, char *argv[ ])
在执行main函数之前,先要调用一个启动例程。可执行文件将此启动例程指定为程序的起始地址。
7.3进程终止
进程有八种终止方式,五个正常终止,三个非正常终止。
正常:
从main返回、调用exit、调用_exit或者_Exit、最后一个线程从其启动例程返回、最后一个线程调用pthread_exit。
非正常:
调用abort、接到一个信号并终止、最后一个线程对取消请求作出响应。
启动例程如果用c语言的格式表示的话。如下:
exit(main(argc, argv))
但是启动例程实际上是汇编语言编写的。
我们可以用下面三个函数正常终止一个程序:
void exit(int status)
vpod _Exit(omt status)
void _exit( int status)
按照ISO C的规定,一个进程可以登记多达32个函数,这些函数将由exit自动调用。并调用atexit函数来登记这些函数。
int atexit(void (*func)( void))
成功返回0,不成功返回非0值。
它的参数是一个函数地址,调用参数函数时不用向其传递任何参数。
下面的程序是atexit函数案例:
atexittest.c:
#include "apue.h"
static void my_exit1(void);
static void my_exit2(void);
int main(void)
{
if (atexit(my_exit2) != 0)
err_sys("can't register my_exit2");
if (atexit(my_exit1) != 0)
err_sys("can't register my_exit1");
if (atexit(my_exit1) != 0)
err_sys("can't register my_exit1");
printf("main is done\n");
return(0);
}
static void my_exit1(void)
{
printf("first exit handler\n");
}
static void my_exit2(void)
{
printf("second exit handler\n");
}
运行结果:
[root@localhost apue]# vim atexittest.c
[root@localhost apue]# gcc atexittest.c
[root@localhost apue]# ./a.out
main is done
first exit handler
first exit handler
second exit handler
7.4命令行参数
当执行一个程序时,调用exec的进程可以将命令行参数传递给该更新程序。
标准要求将argv[argc]设置成一个空指针。
argvtest.c:
#include "apue.h"
int main(int argc, char *argv[])
{
int i;
for (i = 0; argv[i] != NULL; i++)
printf("argv[%d]: %s\n", i, argv[i]);
exit(0);
}
运行结果:
[root@localhost apue]# vim argvtest.c
[root@localhost apue]# gcc argvtest.c
[root@localhost apue]# ./a
access.out a.out apue.h
[root@localhost apue]# ./a.out nihao huang chengdu
argv[0]: ./a.out
argv[1]: nihao
argv[2]: huang
argv[3]: chengdu
7.8存储器分配
ISO C说明了三个用于存储器空间动态分配的函数:
malloc。分配指定字节数的存储区,此存储区的初始值不确定。
calloc。为指定数量的具有指定长度的对象分配存储空间。
realloc。更改以前分配区的长度。
void *malloc( size_t size)
void *calloc( size_t nobj, size_t size)
void *realloc( void *ptr, size_t newsize)
我们可以通过sbrk系统调用来实现对进程的空间的增加或者缩小。
用malloc的常见错误有指针没有初始化、指针用完以后没有调用free函数释放内存,到时内存泄露。
7.9环境变量
环境字符串的形式是:
name = value;
ISO C定义了一个函数getenv,可以用其取环境变量值。
char *getenv( const char *name)
返回值是指向与name关联的value的指针,如果没有找到则返回NULL。
我们可以通过下面三个函数来设置环境变量的值或者删除,新添加环境变量。
int putenv( char *str) //添加
int setenv( const char *name, const char *value, int rewrite) //设置更改
int unsetenv(const char *name) //删除
7.10 setjmp和longjmp函数
这两个函数实现不同函数之间的跳转,setjmp和longjmp。
他们用于在深层次的函数中出现错误后 ,返回到当前函数调用路径上的某个函数中。
int setjmp( jmp_buf env) //直接调用返回0,从longjmp返回则返回非0值。
int longjmp( jmp_buf env, int val)
下面的实例是两个函数的应用:
setjmptest.c:
#include "apue.h"
#include <setjmp.h>
#define TOK_ADD 5
jmp_buf jmpbuffer;
int main(void)
{
char line[MAXLINE];
if (setjmp(jmpbuffer) != 0)
printf("error");
while (fgets(line, MAXLINE, stdin) != NULL)
do_line(line);
exit(0);
}
void cmd_add(void)
{
int token;
token = get_token();
if (token < 0)
longjmp(jmpbuffer, 1);
}
在setjmp中,如果编译用优化模式的话,则局部变量和易失变量(register)不能保存,用关键字volatile保存的局部变量可以保存。
longjmptest.c:
#include "apue.h"
#include <setjmp.h>
static void f1(int, int, int, int);
static void f2(void);
static jmp_buf jmpbuffer;
static int globval = 1;
int main(void)
{
int autoval = 2;
register int regival = 3;
volatile int volaval = 4;
static int statval = 5;
if (setjmp(jmpbuffer) != 0)
{
printf("after longjmp:\n");
printf("globval = %d, autoval = %d, regival = %d, volaval = %d,"
" statval = %d\n", globval, autoval, regival, volaval, statval);
exit(0);
}
globval = 95;
autoval = 96;
regival = 97;
volaval = 98;
statval = 99;
f1(autoval, regival, volaval, statval);
exit(0);
}
static void f1(int i, int j, int k,int l)
{
printf("in f1():\n");
printf("globval = %d, autoval = %d, regival = %d, volaval = %d,"
" statval = %d\n", globval, i, j, k, l);
f2();
}
static void f2(void)
{
longjmp(jmpbuffer, 1);
}
运行结果:
[root@localhost apue]# vim longjmptest.c
[root@localhost apue]# gcc longjmptest.c
[root@localhost apue]# ./a.out
in f1():
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99
after longjmp:
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99
[root@localhost apue]# gcc -O longjmptest.c
[root@localhost apue]# ./a.out
in f1():
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99
after longjmp:
globval = 95, autoval = 2, regival = 3, volaval = 98, statval = 99
7.11getrlimit和setrlimit函数
每个进程都有资源限制,我们可以通过getrlimit和setrlimit函数来实现对这些限制的查询和更改。
int getrlimit(int resource, struct rlimit *rlptr)
int setrlimit(int resource, const struct rlimit *rlptr)
对着两个函数的每一次调用都会指定一个资源以及一个指向下列结构的指针。
struct rlimit{
rlim_t rlim_cur;
rlim_t rlim_max;
}