回顾

gcc 概述

c语言的开发相关文件

  • .c 源文件
  • .o 目标文件
  • .h 头文件
  • .a 静态库
  • .so 共享库文件

环境变量

  • PATH/CPATH/LD_LIBRARY_PATH/

静态库和共享库

动态调用函数(dl系列函数)

  • dlopen 从硬盘打开共享库文件
  • dlsym 从共享库文件中打开函数
  • dlclose 关闭共享库文件
  • dlerror 判定错误

今天

C语言的错误处理
环境表(程序中如何拿到环境变量)
Unix/Linux内存管理

ldconfig

Unix/Linux-02_C

Unix/Linux-02_unix_02


Unix/Linux-02_共享库_03

/lib
/usr/lib
/etc/ld.so.conf 需要root权限,如没权限,使用LD_LIBRARY_PATH

ldd libmy.so 列出共享库的依赖关系

liujing@ubuntu:~/projects/test/lib$ ldd libadd.so 
linux-vdso.so.1 => (0x00007ffc317fd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f923f3d7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f923f9a3000)

liujing@ubuntu:~/projects/test/lib$ ldd a.out
linux-vdso.so.1 => (0x00007fff4fbe3000)
libadd.so => ./libadd.so (0x00007f3065d13000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3065949000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3065f15000)

错误处理

C程序员错误的处理都是通过返回值体现,方式如下:

  • a 返回指针类型的函数,用NULL代表错误(fopen/malloc)
  • b 返回int类型的函数,如果返回的数据不可能是-1 可以用-1 代表错误,非负数代表 正常的返回。
  • c 返回int类型的函数,如果返回的数据有可能是-1,用指针把数据带回,同时用返回值-1代表错误,返回0代表正确。
  • d 如果函数不需要错误处理,可以把返回值写成void。

有以下几个函数,分析一下错误的处理方式
1 比较两个整数,返回最大值 c
2 生成0-9的随机数 随机到0视为错误 b (time/srand/rand)
3 随便返回字符串 a
4 打印一个字符串 d

warning: deprecated conversion from string constant to ‘char*’
char* st = "abc";

官方错误处量

C语言对于错误的处理提供了变量和函数:
C把错误都做成了编号,用​​​外部全局变量errno​​​存储。
错误的信息可以通过编号显示
函数:

  • strerror
  • perror - 最常用
  • printf("%m")

说明

调用C库函数/Unix系统函数时,如果正确,不改变errno,但如果有错误,把错误的编号放入errno中。(不是所有的函数都使用errno)。
不能使用errno判断是否出错,errno只是记录出了什么错

环境表

全局变量environ存储了环境表,环境表是一个字符指针数组(字符串数组),environ就是这个数组的首地址。(​​char **​​​)
环境表有一些操作的函数,包括 setenv/putenv/unsetenv/getenv/clearenv(慎用,清空) 等。

内存管理

STL -> 内存自动分配和回收
|
C++ -> new分配 delete回收 ----- allocator内存分配器 强数据类型
|
C语言 -> malloc/free ---- void*
|
Linux/Unix 系统函数(System call) -> sbrk/brk(都可以分配和回收内存)
|
Linux/Unix 系统调用 -> mmap/munmap 内存映射
| 用户层
|=======================================================
| 内核层(了解)
内核层系统调用 kmalloc/vmalloc/get_free_page …

虚拟内存

Unix/Linux-02_C_04

2的10次方 1KB
2的20次方 1MB
2的30次方 1GB

每个进程都有0-4G的虚拟内存地址空间,但虚拟内存地址只是一个数字,并不能存任何的东西,必须映射到物理内存/文件上才能真正的存储数据。

其中

  • 0G-3G是用户使用,叫用户空间
  • 3G-4G是内核使用,叫内核空间
    用户层的代码只能访问用户空间,无法直接访问内核空间。Unix/Linux系统提供了能进入内核空间的函数,叫系统调用。
    Unix/Linux在管理内存时,以内存页作为最小单位。一个内存页就是4k(4096字节),内存的分配和回收都是内存页作为基本单位。

关于段错误

有以下几种可能:
1 虚拟内存地址没有映射到物理内存
2 做一些没有权限的内存操作(比如:修改只读区)

进程和程序(内存和硬盘)

程序 就是 代码 编译连接之后 保存在硬盘上的可执行文件

进程 就是 运行起来的程序,也就是把 文件加载到内存中

Unix/Linux-02_linux_05

进程的内存空间
每个进程的内存是分区/段的,包括:

  • 1-代码区 : 存放函数中的代码,函数指针就是指向代码区
    代码区 是 只读区
  • 2-全局区(数据段) : 存放全局变量 / static 的变量也在全局区
    全局区在主函数执行之前分配空间
  • 3-BSS段:存放未初始化的全局变量
    BSS段在主函数执行前自动清0
  • 4-堆区 : 也叫自由区,程序员可管理的区域,malloc/free
    字符串字面值(字符串常量) 存在接近代码区的区域,也是只读的。
  • 5-栈区 : 存放局部变量,包括函数的参数
    栈区的内存分配和回收是自动完成的