main函数的原型 int main(int argc, char *argv[]);
argc:命令行参数的个数。
argv:指向这些参数的指针数组。
当一个C程序由内核执行时,在调用main之前会先调用一个起始例程(start-up routine)。该例程从内核中获取命令行参数和环境变量,设置好它们后才开始调用main函数。
进程终止,有8种方法让一个进程终止。
正常终止(5种):
(1):return from main
(2):调用exit函数
(3):调用_exit或者_Exit函数
(4):return of the last thread from its start routine (暂时不知道是什么)
(5):calling pthread_exit from the last thread
异常终止(3种):
(6):调用abort函数
(7):收到一个signal
(8):response of the last thraed to a cancellation request
有关三个exit函数
- #include <stdlib.h>
-
void exit(int status);
-
void _Exit(int status);
- int atexit(void (*func)(void));
-
-
#include <unistd.h>
-
void _exit(int status);
执行该三个函数都会返回内核。 exit函数执行后会执行由atexit注册的函数,关闭标准IO流,然后再返回内核。这三个函数的参数为程序的返回状态(exit status),bash中可以用$?还获得。上面的atexit函数就是用来注册func的,可以注册多个,这样调用exit函数时,会按其注册的顺序的逆序来调用这些函数。
i):调用这三个函数时,没有参数 (这种情况编译器会提醒的)
ii):main的return没有值,即语句"return ;"
iii):main被的返回类型被定义为void
在这三种情况下,exit status的值是不确定的。
下图表示的是C程序的执行和几种结束的方式:
关于上面的atexit函数有这么个问题,如果我用atexit注册的函数foo里也调用了exit函数呢?
环境变量表
程序一般由shell通过fork来执行,fork时会将一个环境变量表传给子程序。环境变量表是一个包含多个字符串指针的数组。 每个数组元素为一个字符串指针,最后一个元素为空指针,每个指针指向一个表示环境变量的字符串,该字符串的形式为:”name=value“。这个数组的地址存在于某个全局变量中。
对环境变量表一般有:查找,添加,修改,删除操作。相应的函数和变量如下:
- extern char **environ;
-
-
#include <stdlib.h>
-
char *getenv(const char *name);
-
// Returns: pointer to value associated with name, NULL if not found
-
-
int putenv(char *str);
-
int setenv(const char *name, const char *value, int rewrite);
-
int unsetenv(const char *name);
- // Returns: 0 if OK, nonzero on error
environ就是环境变量表的地址。getenv通过指定的name获得相应的value串。putenv将str字符串插入环境变量表,如果name重复则删除旧的。setenv将name的值设为value,如果name已存在,当rewrite非0时,先删除旧的定义,当rewrite为0时,则不更新name。unsetenv删除相应的环境变量。处理环境变量的复杂的地方在与添加和修改的时候环境变量表的内存分配问题,此处不细说。
C程序的内存映像,这个看图最清楚了。
size命令可以查看一个二进制文件相应段的大小。
内存分配
- #include <stdlib.h>
-
void *malloc(size_t size);
-
void *calloc(size_t nobj, size_t size);
-
void *realloc(void *ptr, size_t newsize);
-
// Returns: non-null pointer if OK, NULL on error
-
void free(void *ptr);
其中calloc分配的内存都初始化为0。分配内存时可能会用到的系统调用函数为sbrk。
(哇!距离上次写过去了一个半月多,不该偷懒的。我错了)
setjmp & longjmp
C语言中的goto只能在函数内进行跳转,但有时需要跳到函数外去,这时就要用到setjmp和longjmp了。
- #include <setjmp.h>
-
-
int setjmp(jmp_buf env);
-
// Returns: 0 if called directly, nonzero if returning from a call to longjmp
-
-
void longjmp(jmp_buf env, int val);
既然一般进行函数间跳转要用这两个函数,因此env变量一般为全局变量。当第一次遇到setjmp时,setjmp设置env,并返回0。当遇到longjmp后,会跳转到setjmp处,这时setjmp的返回值为val。因此val的值设为非0,而且如果有多个longjmp,我们可以根据val的值来确定是从哪个longjmp跳转回来的。
为保证可移植行,用到setjmp和longjmp的时候最好将局部变量声明为volatile。
getrlimit & setrlimit 函数
- #include <sys/resource.h>
-
-
struct rlimit
-
{
-
rlim_t rlim_cur; /* soft limit: current limit */
-
rlim_t rlim_max; /* hard limit: maximum value for rlim_cur */
-
}
-
-
int getrlimit(int resource, struct rlimit *rlptr);
-
int setrlimit(int resource, const struct rlimit *rlptr);
-
// Both return: 0 if OK, nonzero on error
i)程序可以更改其soft limit使其小于或等于hard limit
ii)进程可以减小其hard limit,但其值要大于或等于soft limit,对于普通用户,该操作不可逆。
iii)只有超级用户进程才能增大hard limit。
一个无限大的limit可以设置为RLIM_INFINITY。这两个函数中resource可以取的值,还是看书或这两个函数的man手册吧。
(完)
阅读(1442) | 评论(0) | 转发(1) |