• linux高级编程day02 笔记


    brk/sbrk
    维护一个位置。 brk/sbrk改变这个位置。
    brk改变绝对位置
    sbrk改变相对位置
     
    昨天的补充:
    永远记住:C的基本类型就那几种。
    所有全新类型都是使用typedef重新定义的。
    类型重定义的好处:
    1. 维护方便
    2. 便于移植(每个系统中都用同一个名,不用修改)
    3. 容易理解
     
    一、 映射虚拟内存
    没有任何额外维护数据的内存分配 mmap/munmap
    1. 函数说明:
    void *mmap(
        void *start,  //指定映射的虚拟地址,如果为0,则由系统指定开始位置
        size_t length,//指定映射空间的大小。 pagesize的倍数
        int prot,     //映射的权限 PROT_NONE    PROT_READ    PROT_WRITE    PROT_WRITE    PROT_EXEC
        int flags,    //映射的方式
        int fd,       //文件描述符号
        offset_t off  //文件中的映射开始位置(必须是0或pagesezi的倍数)
    );
     
    关于映射的方式flags:
    内存映射:又叫匿名映射,最后两个参数无效
    文件映射:映射到某个文件
    只有文件映射,最后两个参数才有效
    MAP_ANONYMOUS:内存映射
    MAP_SHAREDMAP_PRIVATE:二选一,文件映射
     
    2. 案例:
    #include <unistd.h>
    #include <sys/mman.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    int main()
    {
        int *p = mmap(
            NULL,
            getpagesize(),
            PROT_READ|PROT_WRITE,
            MAP_ANONYMOUS|MAP_SHARED,
            0,
            0);
        *P = 20;
        *(p+1) = 30;
        *(p+2) = 40;
        printf("%d\n", p[2]);  //打印出40
        munmap(p, 4096);
    }
      3. 总结:
      选择什么样的内存管理方法?
      STL
      new
      
      malloc小而多的数据
      brk/sbrk同类型的大块数据,动态移动指针
      mmap/munmap 控制内存的访问/使用文件映射/控制内存共享
     
    二、编程工具与动态库
    1. gcc
    2. make
    3. gdb
    4. 其他工具
    5. 动态库(共享库)
     
    1. gcc
    -o 输出文件名
    -O-O1-O2-O3//编译优化
    -g-g1-g2-g3//产生调试信息
    -Wallerror//-Wall 显示所有警告-Werror 将警告当成错误提示
    -w//关闭所有警告
    -c//只编译不连接,产生 .o文件(目标文件)
    -E//预编译
    -S//汇编。 产生 .s文件(汇编文件)
     
    编译过程是 -E-c-S自动调用连接器
    连接器ld
     
    -D//在命令行定义宏 (宏可以在代码中定义,也可以在命令行上定义)
    -x//指定编译的语言类型 C, C++, .S(汇编), none(自动判定)
    -std=c89
    -std=c99
     
    三、 静态库的编译
    1. 编译过程 (*.a) a是achieve的缩写
    1.1 编译成目标文件
    -static 可选
    gcc -c -static 代码文件.c
    1.2 归档成静态库
    ar工具 (常用-r -t选项)
    ar -r 静态文件名被归档的文件名
    ar -r add.aadd.o
    nm工具(查看函数符号表)
    nm 静态库或动态库或目标文件或执行文件
    1.3 使用静态库
    gcc 代码文件 静态库
    小例子:
    使用静态库完成如下程序
    输入一个菱形半径,打印菱形
    输入整型封装成IOTool
    菱形打印封装成Graphic
    计划:
    1. 实现输入
    2. 实现菱形
    3. 编译静态库
    4. 调用静态库
    //iotool.c
    #include <stdio.h>
    int inputInt(const char *info)
    {
        int r;  //返回值
        printf("%s:", info);
        scanf("%d", &r);
        return r;
    }
    //graphic.c
    #include <stdio.h>
    void diamond(int r)
    {
        int x, y;
        for(y=0; y<=2*r; y++)
        {
            for(x=0; x<=2*r; x++)
            {
                if(y == x+r || y == x-r ||y == -x+r || y == -x+3*r)
                {
                    printf("*");
                }
                else
                {
                    printf(" ");
                }
            }
            printf("\n");
    
        }
    }


    编译: gcc -c -static iotool.c

    gcc -c -static graphic.c
    ar -r demo1.a iotool.o graphic.o
    ar -t demo1.a
    nm demo1.a
     
    //main.c
    main()
    {
        int r = inputInt("输入菱形半径:");
        diamond(r);
    }


    编译: gcc main.c demo1.a -o main

    执行:./main
    把静态库作为代码的一部分来编译
     
    总结:
    1. 什么是库?
    函数等代码封装的二进制已经编译的归档文件
    2. ar归档工具
    3. 采用库的方式管理代码优点:
    容易组织代码
    复用
    保护代码版权
    4. 静态库的“静态”的含义:
    编译好的程序运行的时候不依赖库
    库作为程序的一部分编译连接
    5. 静态库的本质
    就是目标文件的集合(归档)
    6. -static可选
     
    2. 库的规范与约定
    库命名规则:
    lib库名.a.主版本号.副版本号.批号
    一般就写“lib库名.a”就行了。
    ar -r libdemo2.a iotool.o graphic.o
    库的使用规则
    -l库名
    -L库所在的目录
    gcc main.c -o main -l demo2 -L.
     
    四、 动态库的编译
    1. 什么是动态库(共享库)
    动态库是可以执行的,静态库不能执行
    但动态库没有main,不能独立执行
    动态库不会连接成程序的一部分
    程序执行时,必须需要动态库文件
    2. 工具
    ldd查看程序需要调用的动态库
    ldd只能查看可执行文件(共享库文件或elf文件)
    readelf -h (-h表示查看执行文件头)
    nm (查看库中的函数符号)
    3. 动态库的编译
    3.1编译
    -c -f pic(可选) (-f 指定文件格式pic 位置无关代码)
    3.2 连接
    -shared
     
    编译:gcc -c -fpic iotool.c
    gcc -c -fpic graphic.c
    (非标准)gcc -shared -odemo3.so iotool.o graphic.o
    (标准)gcc -shared -olibdemo4.so iotool.o graphic.o
    4. 使用动态库
    gcc 代码文件名 动态库文件名
    gcc 代码文件名 -l库名 -L动态库所在的路径
    gcc main.c -ldemo4 -L. -o main
     
    标准命名规则:
    lib库名.so
    lib库名.a
     
    问题:
    4.1 执行程序怎么加载动态库?
    4.2 动态库没有作为执行程序的一部分,为什么连接需要制定动态库及目录?
    因为连接器需要确认函数在动态库中的位置
    动态库的加载:
    1. 找到动态库
    2. 加载动态库到内存(系统实现)
    3. 映射到用户的内存空间(系统实现)
    动态库查找规则:
    /lib
    /user/lib
    LD_LIBRARY_PATH环境变量指定的路径中找
    设置当前路径为环境变量:
    export LD_LIBRARY_PATH=.:~:..:~Walle
    缓冲机制:
    系统把lib:/user/lib:LD_LIBRARY_PATH里的文件加载到缓冲
    /sbin/ldconfig -v 刷新缓冲so中的搜索库的路径
    小练习:
    输入两个数,计算两个数的和。
    要求:输入与计算两个数的和封装成动态库调用
     
    五、 使用libdl.so库
    动态库加载原理
    动态库中函数的查找已经封装成哭libdl.so
    libdl.so里面有4个函数:
    dlopen//打开一个动态库
    dlsym//在打开的动态库里找一个函数
    dlclose//关闭动态库
    dlerror//返回错误
     
    //dldemo.c
    #include <dlfcn.h>
    main()
    {
        void *handle = dlopen("./libdemo4.so", RTLD_LAZY);
        void (*fun)(int) = dlsym(handle, "diamond");
        fun(5);
        dlclose(handle);
    }

      gcc dldemo.c -o main -ldl

      ldd main
      ./main
      
      总结:
      1. 编译连接动态库
      2. 使用动态库
      3. 怎么配置让程序调用动态库
      4. 掌握某些工具的使用 nm ldd lddconfig objdump strit(去掉多余的信息)
     
    六、 工具make的使用与makefile脚本
    背景:
    make编译脚本解释
    编译脚本makefile
    make -f 脚本文件 目标
    脚本文件:
    1. 文本文件  (例如 demo.mk)
    2. 基本构成语法
    基本单位目标target
    目标名:依赖目标
    \t目标指令
    \t目标指令
     
    //demo.mk
    demo:iotool.c graphic.c main.c
        gcc iotool.c -c
        gcc graphic.c -c
        gcc iotool.o graphic.o -shared -o libdemo.so
        gcc main.c -ldemo -L. -o main

    make -f demo.mk demo 会生产main可执行文件

  • 相关阅读:
    struts token令牌机制
    javascript的splice()方法备注
    [转的哦】 Android字符串资源及其格式化Android 中的string.xml用法小结
    3.Android I/O文件写入和读取
    Android开发_读取联系人信息_读取通讯录号码
    ListView的美化涉及到的一些属性
    4.Android添加背景音乐的方法
    Android 网络协议
    ContentValues 和HashTable之间的区别
    5.Andorid绘图方法(Canvas)
  • 原文地址:https://www.cnblogs.com/tangzhengyue/p/2578525.html
Copyright © 2020-2023  润新知