1.五种方式使进程终止
正常:
a.从main返回,自动调用exit
b.调用exit
c.调用_exit
异常:
a.调用abort
b.由一个信号终止
exit和_exit用于正常终止一个程序,exit先执行一些清理工作(包括调用执行各终止处理程序,关闭所有标准I/O流等),然后进入内核。_exit则立即进入内核。
void exit( int exit_code );
void _exit( int exit_code );
2.一个进程可以登记最多32个函数,这些函数由exit自动调用,调用顺序与注册是相反。
登记函数 int atexit( void (*func)(void) );
3.main函数的参数最后一个是NULL
4.每个程序都收到一张环境表,也是一个字符指针数组,其中每个指针包含一个以null结束的字符串的地址。全局变量environ则包含了该指针数组的地址。
extern char**environ;最后一个元素是NULL.
5.程序的存储空间布局
低地址:正文段:cpu执行的机器指令部分。正文段是可共享的,即经常执行的程序在存储哭喊中也只需要有一个副本,正文段常常是只读的,防止指令被修改。
初始化数据段:也称数据段。它包含了程序中需要赋值的全局变量
未初始化数据段:也称BSS段。程序中没有赋值的全局变量
堆
高地址:栈
size命令可以显示程序的正文段,数据段,BSS段大小,单位字节。
6.共享库:使得可执行文件中不再需要包含常用的库函数,只需要在所有进程可以存取的存储区中保留一个函数的副本,程序第一次执行或调用函数时,用动态链接方法
链接此函数。这减少了可执行文件的长度,但增加了运行时间开销。共享库的另一个优点是可以用库函数新版本代替老版本而无需再编译程序。
7.void *malloc(size_t size);//分配指定大小内存,不初始化
void *calloc(size_t n, size_t size);//分配n*size大小内存,初始化0
void *realloc( void *ptr, size_t size );//函数将ptr 对象的储存空间改变为给定的大小size。 参数size可以是任意大小,大于或小于原尺寸都可以。 返回值是指向新空间的指针,如果错误发生返回NULL
realloc(NULL,size)等价于malloc(size)
realloc(ptr,0)//ptr是指向已经动态分配的内存的指针,则相当于free(ptr);
void *alloca(size_t size)//是在栈上动态分配的,自动释放。
8.环境变量
extern char**environ;//环境变量
char *getenv( const char *name );//函数返回环境变量name的值,非常依赖执行情况。如果无对应的环境变量name返回NULL。
int putenv(const char*name)//name的格式是xxx=xx,如果存在会覆盖
int setenv(const char*name,const char*value,int rewrite)//rewrite为1则等价于putenv
9.函数内跳转使用goto,函数之间跳转使用int setjmp(jmp_buf buf);//buf是全局变量,根据返回值判断是哪一个void lognjmp(jmp_buf buf,int val)调用的。val是设置返回值的。
#include<setjmp.h>
#include<stdio.h>
jmp_buf buf;
void f2()
{
longjmp(buf,1);
}
void f1(int a ,int b,int c)
{
printf("in f1() : a = %d, b = %d, c = %d\n",a,b,c);
f2();
}
int main()
{
int a = 1;//普通变量
register int b = 2;//寄存器变量
volatile int c = 3;//易变变量
if(setjmp(buf) != 0)
{
printf("after longjmp : a = %d, b = %d, c = %d\n",a,b,c);
return 0;
}
a = 4,b = 5,c = 6;
f1(a,b,c);
return 0;
}
g++ test.cpp -g //g++默认不优化
./a.out
in f1() : a = 4, b = 5, c = 6
after longjmp : a = 4, b = 5, c = 6
g++ test.cpp -g -o1 //使用一级优化
./a.out
in f1() : a = 4, b = 5, c = 6
after longjmp : a = 1, b = 2, c = 6
以上可见,如果要编写一个使用非局部跳转的可移值程序,要使用volatile属性。
void unsetenv(const char*name)//删除name的定义