10-进程环境

启动代码
main被c程序的启动代码调用
启动代码由谁提供的
(1)启动代码一般是由编译器提供,一般有2种提供方式
1)源码形式(单片机一般)
以源码形式提供时,编译器会将启动代码的源文件和自己的程序的源文件一起编译
  
2)二进制的.o(目标文件)形式
直接以.o形式提供时,省去了对启动代码的编译
  
如果开发的程序是运行在os上的 ,那么编译器一般是以.o的形式来提供启动代码 ,
比如gcc a.c时, gcc就是以.o形式提供的,基于os运行的程序的启动代码,相对裸机的要复杂些
gcc -v可看到很多.o,这些.o就是gcc提供的启动代码
(2)启动代码所做的事
启动代码基本都是汇编编写
在程序的内存空间结构黑没有布局起来之前,高级语言程序还无法运行,此时只能使用汇编,当利用汇编编写的启动代码将高级语言的内存空间结构建立起来之后,自然就可以运行c/c++等高级语言的程序了
大致做两件事
1)对c程序的内存空间进行布局,得到c程序运行所需要的内存空间结构

2)为库的调用预留接口
如果程序使用的是动态库,编译时,动态库代码并不会被直接编译到程序中,只会留下相应的接口,程序运行起来后,才会去对接库代码,为了能够对接动态库,启动代码会留下动态库的对接接口
3)其它等等

程序的运行
1.裸机
1)内存和硬盘一体式 51单片机
2)内存和硬盘分开式

一、程序的正常终止
main函数调用return
a.显式调用
return 0 正常结束
-1 某种操作失败
-2 另外一种失败
./a.out
查看返回值
echo $?

1.
#include <stdio.h>
int func(){
    return 10;
}
int main(int argc, char const *argv[])
{
    printf("php\n");
    
}
返回4
2.
使用子函数返回值
int func(){
    return 10;
}
int main(int argc, char const *argv[])
{
    printf("php\n");
    func();
    
}
返回10
3.
int main(int argc, char const *argv[])
{
    return;
    
}
默认返回-1但是不固定
b.隐式调用 不写return

#include <stdlib.h>

void exit(int status);

#include <stdlib.h>

void _Exit(int status);
_exit是系统函数,exit是库函数
exit通过调用_exit实现
#include <unistd.h>
void _exit(int status);

return,exit,_exit(linux系统)的返回值问题

a.裸机时,无os,只能调用return返回

二、异常终止

进程不是因为以上正常方式而终止的,而是被强行发送了一个信号,这个信号将进程给无条件终止了,就是异常终止
1.自杀:自己调用abort函数,自己给自己发送一个SIGABRT信号将自己杀死
  #include <stdlib.h>
  void abort(void);
2.他杀:由别人发一个信号,将其杀死
  比如ctrl+c
atexit函数
  #include <stdlib.h>
  int atexit(void (*function)(void));
1)功能:注册登记进程终止处理函数 参数就是被登记"进程终止函数"的地址
当进程无论什么时候正常终止时,会自动的去调用登记的进程终止处理函数,实现进程终止时的一些扫尾处理
注意:是正常终止,不是异常
2)返回值
成功返回0,失败返回非0,不会进行错误号的设置

#include <stdlib.h>
#include <stdio.h>
void process_end1(void){
    printf("deal 1\n");
}
void process_end2(void){
    printf("deal 2\n");
}
int main(int argc, char const *argv[])
{
    /* code */
    atexit(process_end1);
    atexit(process_end2);
    printf("over\n");

    return 0;
}

a.调用顺序与注册顺序相反  使用栈存储

b.在linux下,调用atexit最多可允许登记32个终止处理韩式
c.同一个函数被登记多次,也会被调用多次
d.有2中情况,登记的进程终处理函数不会被调用
  1.异常终止
  2.直接调用_exit来正常终止
  就是说,只有使用return 和exit来正常终止时,才会调用

 

进程启动到正常终止
调用exit,return正常终止时,会刷新标准io缓存
标准io的库缓存有三种 无缓冲,行缓冲,全缓冲
(1)行缓冲:标准输出(printf)的库缓存就是行缓存,在缓存中积压的数据,直到出现以下情况时,才会刷新输出,否者一直积压着

 

   1)遇到\n时就刷新输出,\n表示这一行  

int main(int argc, char const *argv[])
                {
                    printf("hello world"); //不加换行不会输出
                    while (1);
                    return 0;
                }

  2)库缓存中数据满了(情况少)
  3)调用fflush函数,会主动刷新数据
  4)调用fclose关闭,会自动调用fflush

 

(2)调用exit正常终止时,会刷新标准Io缓存
exit会调用fclose关闭所有的标准Io,关闭时会自动调用fflush来刷新缓存数据
如果程序是异常退出的,则不会刷新缓存区

 

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    printf("hello world");
    // fflush(stdout);
    printf("----%d",stdout );
    // fclose(stdout);
    //exit(1);
    //_exit(1);
    while (1);
    return 0;
}

 

posted @ 2018-08-27 23:17  H&K  阅读(147)  评论(0)    收藏  举报