一、计算机系统分层
1、什么是操作系统?
操作系统是管理计算机硬件资源和软件资源的一款系统软件,简称OS。
2、计算机系统分层:
操作系统通过驱动程序管理着计算机的硬件资源。
操作系统通过系统调用和用户进行交互。
操作系统层次如下图:
二、环境变量
1、什么是环境变量?
个人总结:bashrc管理永久全局环境变量,bash终端管理临时全局和临时局部环境变量。
程序开始执行时,内核为进程分配环境变量,执行结束,内核释放环境变量。
每个正在执行着的程序,都有属于自己的环境变量。
shell(ubuntu的shell为bash)用一个叫做环境变量的特性来存储有关工作环境的信息。
进程可以通过环境变量访问计算机的资源。
在终端下输入env命令,可以查看此次bash的全局环境变量列表。(同时,全局环境变量才能被子进程继承,局部环境变量无法被子进程继承)
通过echo $name 可以查看某个环境变量的值。
2、环境变量的添加/删除
在终端窗口输入 键=值 形式的内容,回车,添加此次bash进程的局部/自定义环境变量(切记不要加空格)。
比如 FOOD=guobaorou ,表示在当前bash中,为此次bash进程添加名为FOOD,值为guobaorou的局部环境变量(如果环境变量FOOD存在,则更改其值),此时通过env查看不到。
通过export name(如export FOOD)命令,可以将局部环境变量升级为全局环境变量,此时通过env命令可以查看到FOOD这个环境变量。
在此次终端窗口添加的环境变量,在窗口关闭(即此次bash进程结束)后消失,另起一个终端窗口,env命令查看不到FOOD环境变量。这就要在用户家目录的bashrc文件中添加了。
在终端窗口输入 unset name,回车,删除环境变量。
bashrc中的更改的环境变量,要在bashrc中管理,效果才能永久有效。
3、常用的环境变量PATH
PATH环境变量的值是bash进程对命令的检索路径s。
终端中输入echo $PATH ,回车,得到PATH的值(冒号间隔的一堆路径)如下,
/opt/Qt5.12.8/5.12.8/gcc_64/bin:/opt/Qt5.12.8/Tools/QtCreator/bin:/home/tarena/bin:/home/tarena/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
可在终端中输入PATH=$PATH:. 将当前目录.添加到本次bash中,直接输入run.sh可执行,不必费力输入./run.sh。本方法在关闭此终端窗口后失效。
可在.bashrc文件中最后一行添加PATH=$PATH:. (不要加空格、分号),可长期有效地将目录.添加到PATH环境变量中。
在家目录下有.bashrc脚本文件,每次bash进程启动前,都会执行该脚本文件的内容。如果希望环境变量的设置对每个bash进程有效,需将环境变量的设置写在该脚本文件中。
执行 source ~/.bashrc 命令,可使文件立即对当前bash生效,无需重启bash终端。
4、常用的环境变量PS1
该环境变量决定了窗口命令行的提示符内容。
使用 echo $PS1 命令可以查看该环境变量的值。
本人的.bashrc文件末尾对PS1的设置及效果:
export PS1="\[\e[35;1m\]\W$\[\e[0m\]"
将32改为35是绿色。
参考Linux中PS1设置:Linux中PS1设置-comcn2-ChinaUnix博客
三、环境变量表
1、理论
每个进程都有一张独立的环境变量表,其中的每个条目都是一个“键=值”形式的环境变量:
环境变量表就是一个以NULL指针结束的字符指针数组。字符指针数组中的每个元素都是一个字符指针,指向一个以空字符结尾的字符串,该字符串就是“键=值”形式的环境变量。
环境变量表这个字符指针数组的地址保存在全局变量指针environ中:
2、方法一:通过全局环境变量指针environ访问所有环境变量:
extern char** environ;
char** pp;
for(pp = environ; *pp; pp++){
printf("%s\n, *pp);
}
3、方法二:通过main函数的第3个参数envp[](环境变量表的起始地址)访问进程的所有环境变量:
int main(int argc, char* argv[], char* envp[]){
char** pp;
for(pp = envp; *pp; pp++){
printf("%s\n", *pp);
}
return 0;
}
//environ.c 环境变量表
#include<stdio.h>
int main(int argc,char* argv[],char* envp[]){
extern char** environ; //方法1,字符指针数组的首地址environ
/*for(char** pp = environ;*pp;pp++){
printf("%s\n",*pp);
}*/
for(char** pp = envp;*pp;pp++){ //方法2,main函数的第3个参数envp[]
printf("%s\n",*pp);
}
printf("environ = %p\n",environ); //验证两方法得到同一地址
printf("envp = %p\n",envp);
return 0;
}
四、错误处理
运行环境、人为操作等会导致程序执行时发生错误,如果获取出错原因呢?
1、通过错误号 errno
系统于定义的整数类型全局变量errno中存储了最近一次出错的系统调用(不一定就是最近一次系统调用)的错误编号
通过错误编号,可以知道错误原因
头文件 /usr/include/errno.h 中包含了对errno全局变量的外部声明
头文件 /usr/include/asm-generic/errno-bash.h 中包含各种错误号的宏定义
2、通过 strerror() 函数
#include<string.h>
char* strerror(int errnum)
功能:将整数形式的错误号 errno 转换为有意义的字符串
参数:errnum 错误号
返回值:返回与errnum错误号对应的描述字符串
3、通过 perror() 函数
#include<stdio.h>
void perror(char const* tag)
功能:在标准出错设备stdout上打印最近一次函数调用的错误信息
参数:tag 是用户自己制定的提示内容,输出时,会自动在该提示内容和错误信息之间添加
冒号:进行分割。
//error.c 错误处理
#include<stdio.h>
#include<stdlib.h>// malloc() free()
#include<errno.h>// errno
#include<string.h>// strerror()
int main(void){
int* p = malloc(0xffffffffffffffff);
if(p == NULL){
//malloc 失败 --> 原因 --> 编号 --> errno
printf("errno = %d\n",errno); //法1
printf("malloc:%s\n",strerror(errno)); //法2,依赖法1
perror("malloc"); //法3
return -1;
}
free(p);
p = NULL;
return 0;
}
4、通过 errno 错误处理需注意
虽然所有的错误编号都不是零,但因为在函数执行成功的情况下,存储错误编号的全局变量errno并不被清零,所以不能用该变量的值是否为零来作为最近一次函数调用是否成功的判断条件。
正确的做法是,先根据函数的返回值判断其是否出错,在确定出错的前提下,再根据errno的值判断具体出了什么错。