main函数
- C程序总是从main函数开始执行。其原型是:
int main(int argc, char *argc[]);
/*argc是命令行参数的数目,argv是指向参数的各个指针所构成的数组*/
- 内核使程序执行的唯一方法是调用一个exec函数
进程终止
- 进程终止8种方式:
- 从main返回
- exit(自愿)
- _exit或_Exit(自愿)
- 最后一个线程从其启动例程返回
- 从最后一个线程调用pthread_exit
- 调用abort
- 接收一个信号
- 最后一个线程对取消请求做出响应
请看如下经典的”hello world"程序
#include <stdio.h>
main()
{
printf("hello, world!\n");
}
以下是对该程序执行终止后的退出状态码的检查
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ ./hello1
hello, world!
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ echo $?
14
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ gcc -std=c99 hello1.c
hello1.c:3:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main()
^
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ ./a.out
hello, world!
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ echo $?
0
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$
- 其终止码是一个随机的数 14
- 用1999 ISO C编译器扩展,其终止码总是为0
#include <unistd.h>
void _exit(int status);
#include <stdlib.h>
void exit(int status);//输出缓冲区中的所有数据都会被冲洗
void _Exit(int status);
//这些函数都没有返回值,status就是进程终止状态
- 一个进程可登记多至32个函数,在进程终止的时候,这些函数被调用,称为终止处理程序
#include <stdlib.h>
int atexit(void (*function)(void));
- 进程终止处理程序被调用的顺序与他们被登记的顺序刚好相反,请看如下实例
#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");
}
执行结果如下
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ ./doatexit
main is done
first exit handler
first exit handler
second exit handler
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$
命令行参数
下面看一个显示命令行参数的实例,如下:
#include "apue.h"
int
main(int argc, char *argv[])
{
int i;
/*for (i = 0; argv[i] != NULL; i++)*/
for (i = 0; i < argc; i++) /* echo all command-line args */
printf("argv[%d]: %s\n", i, argv[i]);
exit(0);
}
该实例运行结果如下
环境表
- 每个程序都接收到一张环境表,全局参数environ指向一个指针数组,该参数称为环境指针
extern char **environ
如下,是5个字符串组成的环境
每个字符串为一个环境参数,其格式是name=value
C程序的存储空间布局
- 正文段,是CPU执行的机器指令部分。它是可共享的
- 初始化数据段,包含程序中明确赋值的变量
- 未初始化数据段,即bss(block started by symbol)
- 栈,自动变量和每次函数调用时所需保存的信息
- 堆。动态存储分配
如下是一种存储空间的典型分配方式
- 存放在磁盘程序文件中的段只有正文段和初始化数据段
- size命令可以报告正文段、数据段和bss段的长度,例如
共享库
- 共享库是公用函数的集合
- 它减少了可执行文件的长度
- 库函数的版本升级不影响用该库函数的程序
- 但是会增加程序运行时间开销
存储空间分配
以下说明3个用于存储空间动态分配函数
#include <stdlib.h>
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
- 这三个函数返回的指针一定是适当对齐的,使其可用于任何数据对象
- realloc函数可以增、减以前分配的存储区的长度
- 如果忘记用free 释放存储空间,会使进程占用的存储空间连续增加,这被称为内存泄漏
环境变量
#include <stdlib.h>
//取得环境变量的值
char *getenv(const char *name);
int putenv(char *string);//添加或改变环境变量的值
int setenv(const char *name, const char *value, int overwrite);//添加环境变量,overwrite!=0,则覆盖已存在的环境变量的值,否则不改变
int unsetenv(const char *name)//删除环境变量