UC编程基础

一、共享库


-fpic:编译选项,位置为无关码
-shared:链接选项,共享库
LIBRARY_PATH : 链接器使用的库路径环境变量
LD_LIBRARY_PATH : 加载器使用的库路径环境变量
静态加载:在链接阶段链接共享库
gcc main.c -lmath -L.
每次启动a.out程序时,加载器都会加载所需要的共享库
动态加载:在运行阶段通过代码动态地加载共享库,并调用其中的函数。
#include <dlfcn.h>
加载共享库
void* dlopen (
  const char* filename, // 共享库路径
                                     // 若只写文件名,从LD_LIARARY_PATH
                                     // 环境变量所指定的路径下寻找共享库
  int flag // 加载方式:RTLD_LAZY/RTLD_NOW,表示
              // 延迟加载/立即加载
);
成功返回共享库句柄,失败返回NULL
获取函数地址
void* dlsym (
  void* handle, // 共享库句柄
  const char* symbol // 函数名
);
成功返回函数地址,失败返回NULL
卸载共享库
int dlclose (
  void* handle // 共享库句柄
);
成功返回0,失败返回非零
获取错误信息
char* dlerror (void);
有错误发生返回错误信息,否则返回NULL
不需要使用-lmath,但是要用-ldl
辅助工具
nm - 查看目标文件、可执行文件、静态库、共享库中的符号列表
ldd - 查看可执行文件和共享库文件对其它共享库的依赖列表
ldconfig - 共享库管理
事先将共享库的路径信息放入/etc/ld.so.conf.d目录下的一个.conf文件中,通过ldconfig命令将该文件中的共享库路径信息编码为缓冲文件/etc/ld.so.cache,并加载到内存,使之成为共享库搜索路径的另一种方式。每次系统启动时ldconfig命令会自动执行,已形成缓冲。如果修改了共享库的配置,也可以手动执行该命令,更新内存中的缓冲。
strip - 减肥。去掉目标文件、可执行文件、静态和共享库文件中的符号表、调试信息等。

objdump - 反汇编,objdump -S a.out


二、错误处理


1.通过函数的返回值表示错误
1)返回合法值表示成功,返回非法值表示失败。
2)返回有效指针表示成功,返回空指针(NULL/0xFFFFFFFF)表示失败。
3)返回0表示成功,返回-1表示失败,如果有输出数据,可以通过输出参数(指针型参数)返回给调用者。
4)永远成功。如exit()。
2.通过errno表示错误的原因
#include <errno.h> // extern int errno;
1)根据errno得到最近一次错误的编号。
2)将errno错误编号转换为一个有意义的字符串。
#include <string.h>
char* strerror (int errnum);
#include <stdio.h>
void perror (const char* s) {
  printf ("%s: %s\n", s, strerror (errno));
}
printf的%m标记

3)所有的错误的errno都非零,但是不能根据errno为0与否作为判断错误的依据。大多数函数在成功的情况下并不会将errno置为0。


三、环境变量


变量名=变量值
1.环境表
1)每个进程都会接收到一张环境表,是一个以NULL指针结尾的字符指针数组。该数组的每个元素都是一个指向形如xxx=yyy字符串的指针。
2)标准库负责维护环境表的首地址:environ。
2.环境变量函数
getenv - 根据变量名获取变量值
putenv - 以变量名=变量值的形式设置环境变量
               变量名不存在就添加,存在就更新
setenv - 根据变量名设置变量值,如果变量名已存在,则根据参数决
              定是否覆盖原来的变量值
unsetenv - 删除一个已存在的环境变量

clearenv - 清空环境变量,environ == NULL


四、内存管理


STL      内存分配器allocator
C++    new/delete
标C      malloc/calloc/realloc/free
POSIX  brk/sbrk
Linux   mmap/munmap                   用户层
-----------------------------------------------
内核      kmalloc/vmalloc                  系统层
驱动      get_free_page

硬件


五、进程的内存映像


1.程序是保存的磁盘上的可执行文件。
2.进程是把磁盘上的程序加载到内存中的数据块。
3.一个程序可以被加载为多个进程。
4.进程在内存空间中的布局就是进程的内存映像(map)。
从低地址到高地址依次为:
代码区(text):可执行指令、字面值常量、具有常属性且初始化的全局和静态局部变量。只读。
数据区(data):不具常属性但初始化的全局和静态局部变量。
BSS区:未初始化的全局和静态局部变量。
堆区:动态内存分配。从低地址向高地址增长。
栈区:非静态局部变量,包括函数的参数和返回值。从高地址项低地
         址增长。

命令行参数和环境变量区


六、虚拟内存


1.每个进程都拥有各自独立的4G字节的虚拟地址空间。其中0-3G为用户空间,3-4G为内核空间。
2.用户程序中所使用的都是虚拟地址空间中的地址,永远无法直接访问实际的物理内存地址。
3.虚拟内存到物理内存的映射关系由操作系统自动维护。
4.虚拟内存与物理内存之间映射以页为单位。1页=4096字节。
5.虚拟内存一方面保护了操作系统的安全,另一方面允许应用程序使用比半导体内存更大的地址空间。
6.用户空间中的代码不能直接访问内核空间的代码和数据,但是可以通过系统调用间接地与系统内核交互。
7.对内存的越权访问或试图访问没有映射到物理内存的虚拟内存,将导致段错误。
8.用户空间对应进程,进程一切换,用户空间就会随之变化。内核空间由操作系统内核管理,不会随着进程切换而改变。内核空间由内核根据独立且唯一的映射表(init_mm.pgd)进行内存映射,而用户空间的映射表则是每个进程一份。

9.每个进程的用户空间是完全独立的,因此在不同进程之间交换虚拟地址是毫无意义的。


七、堆内存分配


malloc/calloc/reaclloc/free
1.堆内存分配函数除了分配用户所要求的内存以外,还需要多分配一些内存供其自身使用。对多出的部分不用轻易操作,否则将引发未定义的行为。
2.堆内存分配函数在分配内存的过程中,需要建立虚拟内存到物理内存的映射,它们所实际映射的内存会比用户需要的多:
1)映射总是以页为单位;
2)首次映射33页。
3.获取页大小
#include <unistd.h>
int getpagesize (void);
返回内存页大小。
char* pc = malloc (sizeof (char));
           |
          V<-------------------33页-------------------->|
-------+-------+------------+-------------------------+------------
           | 1字节 |   控制数据  |                                     | 
-------+-------+------------+-------------------------+------------
    ^          ^            ^                          ^                          ^
 段错误     OK      后续错误                不稳定                    段错误
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值