1. main函数和进程终止
当内核执行C程序时,在调用main前先调用一个特殊的启动例程。可执行程序文件将此启动例程指定为程序的起始地址。启动例程从内核取得命令行参数和环境变量值,然后调用main函数。
而有8种方式使进程终止:
5种正常终止:
1) 从main返回。 2)调用exit。 3) 调用_exit或_Exit。 4) 最后一个线程从其启动例程返回。 5) 最后一个线程调用pthread_exit。
3种异常终止:
1) 调用abort。 2) 接到一个信号并终止 3) 最后一个线程对取消请求做出响应
经典的C程序:
#include <stdio.h>
main()
{
printf("hello, world\n");
}
程序运行结果:
一个进程可以登记多达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");
}
程序输出:
2. C程序的存储空间布局
1. 正文段:由CPU执行的机器指令部分
2. 初始化数据段:包含了程序中需明确的赋初值的变量
3. 非初始化数据段: 声明在函数之外的变量存放的地方
4. 栈:自动变量以及每次函数调用时所需保存的信息都存放在此段中
5. 堆:进行动态分配
3. 关于环境变量
#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;
}
程序输出:
4. 只调用最近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 );
}
程序输出: