1、退出函数
//_exit,_Exit直接进入内核,exit先执行一些清理操作,再进入内核
//ISO C
#include <stdlib.h>
void exit(int status);//exit(0)等于return(0)
void _Exit(int status);
//POSIX
#include <unistd.h>
void _exit(int status);
2、终止处理登记
//退出时会调用这些登记的函数,方向和登记风向相反
int atexit(void (*fun)(void));//成功返回0
//内核使程序执行的唯一方法是调用一个exec函数
#include "apue.h"
static void myexit1(void);
static void myexit2(void);
int main(void)
{
if(atexit(myexit2)!=0)
err_sys("can't register myexit2");
if(atexit(myexit1)!=0)
err_sys("can't register myexit1");
if(atexit(myexit1)!=0)
err_sys("can't register myexit1");
printf("main is done\n");
}
static void myexit1(void)
{
printf("first exit handler\n");
}
static void myexit2(void)
{
printf("second exit handler\n");
}
3、命令行参数,环境表
//argv[argc]=NULL
int main(int argc, char *argv[])
extern char **environ;
//environ为指向*environ(environ[0])的指针,environ[0]也是一个指针
一级指针作为形参传递,可以修改指针指向的内容,但是要是需要修改指针本身则要传递二级指针。
4、C程序的存储空间布局,需要存放在磁盘的只有正文段和初始化数据段
(1)正文段:CPU执行的机器指令部分
(2)初始化数据段:有明确初值的变量
(3)为初始化数据段:bss段,程序执行前内核将其清零
(4)栈
(5)堆
5、共享库
共享库使得可执行文件中不再需要包含公用的函数库,而是在所有进程都可以引用的存储区中保存这种库例程的一个副本。程序第一次执行或者第一次调用某个函数时,用动态链接的方法将程序与共享函数相链接。
6、存储空间分配
void *malloc(size_t size);
//为指定数量指定长度的对象分配存储空间
void *calloc(size_t nobj, size_t size);
//当原连续空间不够,则先把原来数据复制到新空间,再在新空间扩展。所以不能再使用原来的地址。
void *realloc(void *ptr, size_t newsize);
7、环境变量,name = value
#include <setjmp.h>
char *getenv(const char *name);
int putenv(char *str);//把str=“name=value”字符串放到环境表中
int setenv(const char *name, const char *value, int rewrite);
int unsetenv(const char *name);
8、函数setjmp和longjmp
//goto语句不能跨越函数
int setjmp(jmp_buf env);//直接调用返回0,从longjmp返回,为longjmp中val;env保存原来环境,1个setjmp可以对应多个val不同的longjmp
void longjmp(jmp_buf env, int val);
jmp_buf jmpenv;
int main()
{
if(setjmp(jmpenv) != 0)
{
//进行一些处理
exit(0);
}
fun();
}
int fun()
{
longjmp(jmpenv, 1)
}
9、不同变量类型
不进行优化时,变量存于存储器中,进行优化时自动变量、寄存器变量可能存于寄存器中,值会发生变化。全局变量、静态变量、易失变量不受影响。
自动变量在函数结束会被回收,后面继续使用会出错
#include "apue.h"
#include <setjmp.h>
static void f1(int, int, int, int);
static void f2(void);
static jmp_buf jmpenv;
static int globval;
int main(void)
{
int autoval;
register int regival;
volatile int volaval;
static int statval;
globval=1;autoval=2;regival=3;volaval=4;statval=5;
if(setjmp(jmpenv) != 0){
printf("after longjmp:\n");
printf("global=%d, autoval=%d, regival=%d, volaval=%d, statval=%d\n",globval, autoval, regival, volaval, statval);
exit(0);
}
globval=91;autoval=92;regival=93;volaval=94;statval=95;
f1(autoval, regival, volaval,statval);
exit(0);
}
static void f1(int i, int j, int k, int l)
{
printf("in f1():\n");
printf("global=%d, autoval=%d, regival=%d, volaval=%d, statval=%d\n",globval, i, j, k, l);
f2();
}
static void f2(void)
{
longjmp(jmpenv, 1);
}
~
$ gcc myval.c
$ ./a.out
in f1():
global=91, autoval=92, regival=93, volaval=94, statval=95
after longjmp:
global=91, autoval=92, regival=93, volaval=94, statval=95
$ gcc -O myval.c
$ ./a.out
in f1():
global=91, autoval=92, regival=93, volaval=94, statval=95
after longjmp:
global=91, autoval=2, regival=3, volaval=94, statval=95
9、getrlimit和setrlimit
//每个进程都有一组资源限制,进程资源限制通常在系统初始化时0进程建立,然后由后继进程继承。
//资源限制影响到调用进程并由其子进程继承,所以用户的所有后续进程都会受影响。
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlptr);
int setrlimit(int resource, const struct rlimit *rlptr);
//用户可以减少硬限制,但必须大于等于软限制,只有root可以提高硬限制
struct rlimit{
rlim_t rlim_cur;//软限制:当前限制
rlim_t rlim_max;//硬限制:当前限制的最大值
};
# 为ISO C字符串创建符
#define doit(name) pr_limits(#name, name)
doit(RLIMIT_CORE)=pr_limits("RLIMIT_CORE", RLIMIT_CORE)