main函数和进程终止
当内核执行C程序时,在调用main前先调用一个特殊的启动例程。可执行程序文件将此启动例程指定为程序的起始地址。启动例程从内核取得命令行参数和环境变量值,然后调用main函数。
存在8种方式终止进程:
5种正常终止:
1. 从main返回
2. 调用exit
3. 调用_exit或者_Exit
4. 最后一个线程从启动例程中返回.
5. 最后一个线程调用pthread_exit.
3种异常终止:
1. 调用abort
2. 接收信号并终止.
3. 最后一个线程对取消请求做出响应.
Exit函数
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
_exit和_Exit会立马返回到内核, 而exit则会清除线程后返回内核.
在main函数中, 如果没有显式return/exit, 则默认返回0:
#include <stdio.h>
int main(void)
{
printf("hello world\n");
}
终端输出:
leicj@leicj:~/test$ ./a.out
hello world
leicj@leicj:~/test$ echo $?
0
atexit函数
一个进程可以登记多达32个函数,这些函数将由exit自动调用。我们称这些函数为终止处理程序,并调用atexit函数来登记这些函数。
终止处理程序:
#include <stdio.h>
static void my_exit1(void);
static void my_exit2(void);
int main(void)
{
if (atexit( my_exit2 ) != 0)
printf("can't register my_exit2\n");
if (atexit( my_exit1 ) != 0)
printf("can't register my_exit1\n");
if (atexit( my_exit1 ) != 0)
printf("can't register my_exit1\n");
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");
}
程序输出:
leicj@leicj:~/test$ ./a.out
main is done
first exit handler
first exit handler
second exit handler
C程序的存储空间布局
1. 正文段:由CPU执行的机器指令部分
2. 初始化数据段:包含了程序中需明确的赋初值的变量
3. 非初始化数据段: 声明在函数之外的变量存放的地方, 通常会被内核初始化为0或者null.
4. 栈:自动变量以及每次函数调用时所需保存的信息都存放在此段中
5. 堆:进行动态分配
leicj@leicj:~/test$ size /usr/bin/cc /bin/sh
text data bss dec hex filename
902577 8048 9696 920321 e0b01 /usr/bin/cc
143301 4792 11312 159405 26ead /bin/sh
内存分配
ISO C定义三个函数用于分配内存, 一个函数用于释放内存.
#include <stdlib.h>
void *malloc(size_t size);
void *calloc(size_t nobj, size_t size);
void *realloc(void *ptr, size_t newsize);
returns: 成功返回非空指针, 失败返回NULL
void free(void *ptr);
malloc: 分配特定字节的内存, 初始值不确定.
calloc: 分配特定数量的对象, 每个对象的大小为size.
realloc: 用于增加或减少内存.
关于环境变量
#include <stdio.h>
#include <stdlib.h>
extern char *environ;
int main( void )
{
putenv("hello=world");
setenv("hello1", "world1", 0);
printf("%s\n", getenv("hello"));
printf("%s\n", getenv("hello1"));
unsetenv("hello");
unsetenv("hello1");
return 0;
}
程序输出:
leicj@leicj:~/test$ ./a.out
world
world1
setjmp和longjmp
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmpbuffer;
void fun1();
void fun2();
int main( void )
{
int bFun1 = 0;
int bFun2 = 0;
bFun1 = setjmp(jmpbuffer);
bFun2 = setjmp(jmpbuffer);
printf("the return value is:%d---%d\n", bFun1, bFun2);
printf("main done\n");
if ( bFun1 || bFun2 ) {
exit( 0 );
}
fun1();
fun2();
return 0;
}
void fun1()
{
printf("fun1\n");
longjmp( jmpbuffer, 1 );
}
void fun2()
{
printf("fun2\n");
longjmp( jmpbuffer, 2 );
}
程序输出:
leicj@leicj:~/test$ ./a.out
the return value is:0---0
main done
fun1
the return value is:0---1
main done
来源:oschina
链接:https://my.oschina.net/u/1017135/blog/337345