1.当执行程序时,main函数是如何被调用的
1)C程序总是从main函数开始执行,main函数的原型
int main(int argc,char *argv[])
2)
a.C程序的执行是内核通过调用exec函数,在调用C的main前先调用一个特殊的启动例程(通过由汇编写成),
b.C程序的可执行文件将此启动例程定为C程序可执行文件的起始地址(链接编辑器设置(由gcc调用))
c.启动例程从内核取得命令行参数和环境变量值
d.为调用main函数做好其它安排
2.命令行参数是如何传递给执行程序的
当执行一个程序时,调用exec的进程可以推命令行参数传递给该新程序
For(i=0;argv[i]!=NULL,i++)可以用来遍历参数表
3.典型的存储器布局是什么样式
C程序一直由下面几部分组成:
1) 正文段。这是由CPU执行的机器指令部分。通常,正文段是可共享的,所以即即使是频繁执行的程序在存储器中也只需有一个副本,另外,正文段常常是只读的,以防止程序由于意外而修改其自身的指令
2) 初始化数据段。通常此段称为数据段,它包含了程序中需要明确地赋初值的变量,如函数外声明int maxcount=99;
3) 非初始化数据段。通常将此段称为bss段,在程序开始执行之前,内核将此段中的数据初化为0或空指针。出现在任何函数外的C声明long sum[1000];
4) 栈。自动变量以及每次函数调用时民需保存的信息都存放在此段中。每次调用函数时,其返回地址以及调用者的环境信息都存放在栈中。然后最近被调用的函数在本息为其自动变量和临时变量分配存储空间。通过此方式使用栈可以递归调用C函数。递归函数每次调用自身时,就使用一个新的栈帧,因此一个函数调用实例中的变量集不会影响另一个函数调用实例的变量
5) 堆。通常在堆中进行动态存储分配。
在x86处理器上的linux,正文段人0x08048000单元开始,栈底则在0xc00000000这上
可以用size来命令报告正文段,数据库和bss段的长度(单位:字节)
4.如何分配另外的存储空间
1)malloc.分配指定字节数据的存储区,此存储区中的初始值不确定
2)calloc.为指定数量具指定长度的对象分配存储空间。该空间每一个位都初始人为0
3)realloc.增加或减少长度。新增的地方的初始值不确定
#include<stdlib.h>
Void *malloc(size_t size)
Void *calloc(size_t nobj,size_t size)
Void *realloc(void *ptr,size_t newsize);
Void free(void*ptr)
这三个分配函数所返回的指针是一定是适当对齐的
返回的指针赋予一个不同类型的指针时,不要需要显式进行类型强制转换
5.进程如何使用环境变量
#include<stdlib.h>
Int main(){
Char*p;
If((p=getenv(“USER”)))
Printf(“USER=%s\n”,p);
}
#include<stdlib.h>
Int putenv(char *str);
Int setenv(const char*name,constchar*value,int rewrite)
Int unsetenv(const char*name)
6.终止进程的方式
正常方式:
1)从main返回
2)调用exit
a.ISOC说明的
#include<stdlib.h>
void exit(int status);
void _Exit(int status);
b.在main函数中exit(0)等价于return(0);
c.先执行一些清理处理(如调用执行各终止处理程序,关闭所有标准I/O流)然后进入内核
d.终止处理程序的登记-atexit,
exit调用的时候会调用登记的处理程序,顺序和登记时相反,同一函数登记多次也会调用多次。然后在按需多次调用fclose
#include<stdlib.h>
int atexit(void (*func)(void));
3)调用_exit或_Exit
是由POSIX.1说明的
#include<unistd.h>
void _exit(int status)
立即进入内核
4)最后一个线程从它的启动例程返回
5)最后一个线程调用pthread_exit
异常方式:
6)调用abort
7)接到一个信号并终止
8)最后一个线程对取消请求做了响应
启动例程在C程序从main返回后会调用exit.
1) 内核使程序执行的唯一方式是调用一个exec
2) 进程自愿终止的唯一方法是通过exit调用_exit或_exit
3) 进程也可非自愿由一个信号使其终止
7.longjmp和setjmp函数以及它们与栈的交互作用
Goto函数语句不能跨越函数的,而执行这类跳转的是函数setjmp和longjmp.
这两个可以在栈上跳过若干调用帧,返回到当前函数调用路径上的某个函数中
#include<setjmp.h>
Int setjmp(jmp_buf env);
Void longjmp(jmp_buf env,int val);
Env存放着调用longjmp时能用来恢复栈的所有信息,env应该设置为全局变量
在longjmp后,原来的自动变量值就变为不确定了,若不想它回滚,可以定义为volitile
声明为全局变量或静态变量的值在执行longjmp时保存不变
自动变量
全局变量
寄存器变量
静态变量
易失变量
8.进程的资源限制
每个进程都有一组资源限制,其中一些可以用getrlimit()和setrlimit()进行查询和更改
#include<sys/resource.h>
Int getrlimit(int resource,struct rlimit*rlptr);
Int setrlimit(int resource,const structrlimit *rlptr);
1) 任何一个进程都可将一个软限制值更改为小于或等于其硬限制值
2) 任何一个进程都可降低其硬限制值,但它必须大于或等于其软件限制,对于普通用户是不可逆的
3) 只有超级用户进程可以提高硬限制的值
一个进程如何引起一个程序被执行,如何等待它的完成和如何取其终止状态