深入理解 Linux 动静态库:从制作到加载的完整指南

CST 仿真_NFC仿真 在CST中实现NFC天线单体的仿真 阅读详情

        在 Linux 开发中,库是代码复用的核心载体,几乎所有程序都依赖底层库实现功能。无论是编写工具脚本还是大型应用,理解动静态库的原理与使用都至关重要。本文将从库的基础概念出发,详细讲解动静态库的制作、使用、ELF 文件格式,以及程序加载的底层机制,帮助你彻底掌握这一核心技术。

一、认识库:程序的 "预制构件"

库本质是可复用的二进制可执行代码,能被操作系统载入内存执行。它解决了 "重复造轮子" 的问题 —— 开发者无需从零实现基础功能(如文件操作、字符串处理),直接调用库接口即可。

1.1 库的两种核心类型

Linux 系统中,库主要分为静态库和动态库,二者在编译链接方式、文件格式和使用场景上差异显著:

类型Linux 后缀Windows 后缀核心特点适用场景
静态库.a.lib编译时将代码嵌入可执行程序,运行时无需依赖库文件追求程序独立性、无依赖部署(如嵌入式设备)
动态库.so.dll编译时仅记录函数入口,运行时动态加载库代码多程序共享库、节省内存与磁盘空间(如系统工具)

1.2 系统默认库的位置

Linux 系统预装了 C/C++ 标准库等基础库,不同发行版路径略有差异:

        Ubuntu 系统:

                C 标准库:/lib/x86_64-linux-gnu/libc-2.31.so(动态)、/lib/x86_64-linux-gnu/libc.a(静态)

              C++ 标准库:/usr/lib/gcc/x86_64-linux-gnu/9/libstdc++.so(动态)、/usr/lib/gcc/x86_64-linux-gnu/9/libstdc++.a(静态)

        CentOS 系统:

                C 标准库:/lib64/libc-2.17.so(动态)、/lib64/libc.a(静态)

      C++ 标准库:/lib64/libstdc++.so.6(动态)、/usr/lib/gcc/x86_64-redhat-linux/4.8.2/libstdc++.a(静态)

通过ls -l命令可查看库文件的权限、大小和修改时间,例如:

# 查看Ubuntu下的C动态库
ls -l /lib/x86_64-linux-gnu/libc-2.31.so
# 输出:-rwxr-xr-x 1 root root 2029592 May 1 02:20 /lib/x86_64-linux-gnu/libc-2.31.so

二、静态库:编译时 "打包" 代码

静态库的核心是编译链接阶段将库代码完整嵌入可执行程序,生成的程序可独立运行,无需依赖外部库文件。下面以自定义的my_stdio(文件操作)和my_string(字符串处理)库为例,讲解静态库的制作与使用。

2.1 准备基础代码

首先编写库的头文件和实现文件,封装基础功能:

        my_stdio.h:声明文件操作接口(mfopen、mfwrite、mfflush、mfclose)

#pragma once
#define SIZE 1024
#define FLUSH_NONE 0
#define FLUSH_LINE 1
#define FLUSH_FULL 2

struct IO_FILE {
    int flag;       // 刷新方式
    int fileno;     // 文件描述符
    char outbuffer[SIZE];
    int cap;
    int size;
};
typedef struct IO_FILE mFILE;

mFILE *mfopen(const char *filename, const char *mode);
int mfwrite(const void *ptr, int num, mFILE *stream);
void mfflush(mFILE *stream);
void mfclose(mFILE *stream);

        my_stdio.c:实现文件操作逻辑(基于系统调用open、write、fsync)

        my_string.h:声明字符串处理接口(my_strlen)

#pragma once
int my_strlen(const char *s);

        my_string.c:实现字符串长度计算逻辑

2.2 制作静态库:使用ar工具

静态库的制作分两步:编译生成目标文件(.o) → 打包目标文件为静态库(.a)。推荐使用Makefile自动化构建,提高效率。

2.2.1 编写 Makefile
# 目标:静态库文件名
libmystdio.a: my_stdio.o my_string.o
    # ar -rc:替换(replace)并创建(create)静态库
    @ar -rc $@ $^
    @echo "build $^ to $@ ... done"

# 编译所有.c文件为.o文件
%.o: %.c
    @gcc -c $<  # -c:仅编译不链接
    @echo "compiling $< to $@ ... done"

# 清理中间文件
.PHONY: clean
clean:
    @rm -rf *.a *.o stdc*
    @echo "clean ... done"

# 输出库文件到标准目录结构(便于部署)
.PHONY: output
output:
    @mkdir -p stdc/include stdc/lib
    @cp -f *.h stdc/include  # 头文件放入include
    @cp -f *.a stdc/lib      # 静态库放入lib
    @tar -czf stdc.tgz stdc  # 打包为压缩包
    @echo "output stdc ... done"
2.2.2 执行构建与验证

运行make命令生成静态库,再用ar -tv查看库内包含的目标文件:

# 构建静态库
make
# 查看库内容(t:列表,v:详细信息)
ar -tv libmystdio.a
# 输出示例:
# rw-rw-r-- 1000/1000 2848 Oct 29 14:35 2024 my_stdio.o
# rw-rw-r-- 1000/1000 1272 Oct 29 14:35 2024 my_string.o

2.3 使用静态库:编译链接三要素

使用静态库时,编译器需要知道头文件路径(-I)、库文件路径(-L) 和库名(-l)。以下是三种常见使用场景:

场景 1:库文件安装到系统路径

若将头文件复制到/usr/include、库文件复制到/usr/lib,可直接链接:

gcc main.c -lmystdio  # -lxxx:链接名为libxxx.a的静态库
场景 2:库文件与源文件同目录

通过-L.指定库路径为当前目录:

gcc main.c -L. -lmystdio
场景 3:库文件在自定义路径

通过-I指定头文件路径,-L指定库路径:

# 假设头文件在./include,库文件在./lib
gcc main.c -I./include -L./lib -lmystdio

2.4 静态库的关键特性

        独立性:生成的可执行程序不依赖静态库文件,删除库后程序仍可运行。

        体积大:库代码嵌入程序,若多个程序使用同一静态库,会重复占用磁盘和内存。

        更新难:若库功能需要更新,必须重新编译所有依赖该库的程序。

三、动态库:运行时 "共享" 代码

动态库的核心是编译时仅记录函数入口地址,运行时动态加载库代码。多个程序可共享同一动态库的内存副本,大幅节省资源。

3.1 制作动态库:-fPIC与-shared

动态库的制作同样需要编译目标文件,但需添加-fPIC(生成位置无关代码),再用-shared链接为动态库。

3.1.1 编写 Makefile
# 目标:动态库文件名
libmystdio.so: my_stdio.o my_string.o
    # -shared:生成共享库格式
    @gcc -o $@ $^ -shared
    @echo "build $^ to $@ ... done"

# 编译目标文件:-fPIC生成位置无关代码(动态库必需)
%.o: %.c
    @gcc -fPIC -c $<
    @echo "compiling $< to $@ ... done"

# 清理与输出(同静态库)
.PHONY: clean
clean:
    @rm -rf *.so *.o stdc*
    @echo "clean ... done"

.PHONY: output
output:
    @mkdir -p stdc/include stdc/lib
    @cp -f *.h stdc/include
    @cp -f *.so stdc/lib
    @tar -czf stdc.tgz stdc
    @echo "output stdc ... done"
3.1.2 关键参数解析

  -fPIC:生成位置无关代码(Position Independent Code)。动态库加载到内存的地址不固定,PIC 确保代码可在任意地址执行,无需修改指令。

  -shared:告诉编译器生成共享库格式,而非可执行程序。

3.2 使用动态库:编译与运行时依赖

动态库的编译链接方式与静态库一致,但运行时需确保系统能找到动态库,否则会报错。

3.2.1 编译链接
# 场景2:库文件与源文件同目录
gcc main.c -L. -lmystdio
# 生成可执行程序a.out
3.2.2 运行时找不到库的问题

直接运行程序可能报错,用ldd命令可查看程序依赖的动态库:

# 查看a.out的动态库依赖
ldd a.out
# 输出示例(关键行:libmystdio.so => not found)
# linux-vdso.so.1 => (0x00007fff4d396000)
# libmystdio.so => not found  # 找不到动态库
# libc.so.6 => /lib64/libc.so.6 (0x00007fa2aef30000)
3.2.3 解决方案:4 种动态库搜索路径配置

Linux 动态链接器(ld-linux.so)按以下优先级搜索动态库,可通过任意一种方式配置:

  1. 复制到系统共享库路径将动态库复制到/usr/lib、/usr/local/lib或/lib64(系统默认搜索路径):

    sudo cp libmystdio.so /usr/lib
    
  2. 建立软链接若不想复制文件,可在系统路径下建立软链接:

    sudo ln -s /path/to/libmystdio.so /usr/lib/libmystdio.so
    
  3. 修改环境变量LD_LIBRARY_PATH临时指定动态库搜索路径(终端关闭后失效):

    # 方式1:临时生效
    export LD_LIBRARY_PATH=/path/to/lib:$LD_LIBRARY_PATH
    # 方式2:永久生效(写入~/.bashrc)
    echo 'export LD_LIBRARY_PATH=/path/to/lib:$LD_LIBRARY_PATH' >> ~/.bashrc
    source ~/.bashrc
    
  4. 配置ld.so.conf并更新缓存系统级配置(推荐用于全局部署):

    # 1. 在/etc/ld.so.conf.d/下创建配置文件
    sudo echo "/path/to/lib" > /etc/ld.so.conf.d/mystdio.conf
    # 2. 更新动态库缓存
    sudo ldconfig
    

3.3 动态库的核心优势

        资源节省:多个程序共享同一动态库的内存副本,减少磁盘和内存占用。

        易于更新:更新动态库后,所有依赖该库的程序无需重新编译,直接运行即可生效。

        体积小:可执行程序仅包含函数入口地址表,体积远小于静态链接的程序。

四、深入 ELF:理解程序的 "基因序列"

无论是可执行程序、静态库还是动态库,在 Linux 中都以ELF(Executable and Linkable Format) 格式存储。理解 ELF 是掌握程序编译、链接和加载的关键。

4.1 ELF 的四种文件类型

ELF 格式涵盖四种核心文件,对应开发和运行的不同阶段:

文件类型后缀用途示例
可重定位文件.o编译生成的目标文件,用于链接成可执行程序或动态库my_stdio.o
可执行文件无后缀可直接运行的程序,包含完整的执行逻辑a.out、/bin/ls
共享目标文件.so动态库,运行时加载libmystdio.so、libc.so.6
内核转储文件core进程崩溃时生成的内存快照,用于调试core.12345

用file命令可查看文件类型:

# 查看目标文件类型
file my_stdio.o
# 输出:my_stdio.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

# 查看可执行文件类型
file a.out
# 输出:a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked

4.2 ELF 文件的四大组成部分

ELF 文件的结构类似 "洋葱",从外到内分为四层,每层承担不同职责:

  1. ELF 头(ELF Header)位于文件最开头,记录文件的基本信息,如文件类型、机器架构、入口地址,以及程序头表和节头表的位置。用readelf -h可查看:

    readelf -h a.out
    
  2. 程序头表(Program Header Table)描述文件如何加载到内存,将多个节(Section)合并为段(Segment)。操作系统加载程序时,根据程序头表分配内存并设置权限(如可读、可写、可执行)。用readelf -l可查看:

    readelf -l a.out
    
  3. 节头表(Section Header Table)描述文件中的所有节(Section),如代码节(.text)、数据节(.data)。链接器(如ld)通过节头表处理目标文件,合并相同功能的节。用readelf -S可查看:

    readelf -S a.out
    
  4. 节(Section)ELF 文件的最小功能单元,不同节存储不同类型的数据:

    • .text:存放机器指令(代码),权限为 "只读 + 可执行"。
    • .data:存放已初始化的全局变量和静态变量,权限为 "可读 + 可写"。
    • .rodata:存放只读数据(如字符串常量),权限为 "只读"。
    • .bss:为未初始化的全局变量和静态变量预留空间,文件中不占用磁盘空间,加载时分配内存并清零。
    • .symtab:符号表,记录函数名、变量名与地址的映射关系。

4.3 ELF 的两个核心视图

ELF 文件提供两种视图,分别对应链接阶段和运行阶段,帮助工具(链接器、操作系统)理解文件结构:

4.3.1 链接视图(Linking View)

以节头表为核心,关注代码和数据的功能划分。链接器(如ld)将多个.o文件的.text节合并为一个大的.text节,.data节同理,同时修正函数和变量的地址(重定位)。

4.3.2 执行视图(Execution View)

以程序头表为核心,关注文件如何加载到内存。操作系统将属性相同的节(如.text、.rodata)合并为段(Segment),例如:

        只读可执行段:包含.text、.rodata,加载到内存后权限为 "只读 + 可执行"。

        可读可写段:包含.data、.bss,加载到内存后权限为 "可读 + 可写"。

合并段的目的是减少内存碎片:若.text为 4097 字节、.rodata为 512 字节,单独加载需 3 个 4KB 内存页,合并后仅需 2 个页,大幅提高内存利用率。

五、链接与加载:程序从代码到运行的蜕变

程序的生命周期分为 "编译→链接→加载→运行" 四个阶段,其中链接和加载是连接代码与运行的关键环节。静态链接和动态链接的差异,本质是这两个阶段的分工不同。

5.1 静态链接:编译时完成 "组装"

静态链接的核心是将所有目标文件(.o)和静态库(.a)合并为一个可执行程序,并完成地址修正(重定位)。

5.1.1 静态链接的过程
  1. 合并目标文件:将用户编写的.o文件(如main.o、my_stdio.o)与静态库中的.o文件(如libc.a中的printf.o)合并。
  2. 地址重定位:编译生成的.o文件中,函数调用地址为临时值(如0x00000000)。链接器根据符号表(.symtab)找到函数的实际地址,修正指令中的跳转地址。

例如,main.o中调用run函数的指令原本为e8 00 00 00 00(跳转地址为 0),链接后修正为e8 cb ff ff ff(实际跳转地址为0x1149)。用objdump -d可查看修正前后的差异:

# 查看链接前的main.o(地址未修正)
objdump -d main.o
# 查看链接后的a.out(地址已修正)
objdump -d a.out
5.1.2 静态链接的优缺点

        优点:可执行程序独立运行,无外部依赖;加载速度快(无需运行时链接)。

        缺点:程序体积大;多个程序重复包含同一库代码,浪费资源;库更新需重新编译程序。

5.2 动态链接:运行时完成 "绑定"

动态链接将链接过程推迟到程序加载时,核心是通过全局偏移表(GOT) 和过程链接表(PLT) 实现动态地址绑定,解决静态链接的资源浪费问题。

5.2.1 动态链接的核心挑战

静态链接中,代码段(.text)的地址在编译时确定,可直接修正。但动态库加载地址不固定,且代码段为只读(无法修改指令),如何实现函数调用?

解决方案是将地址存储在可写的数据段(.data)中—— 即全局偏移表(GOT)。GOT 是数据段中的一张表,记录动态库函数的实际地址,链接器在运行时修改 GOT 表,而非代码段。

5.2.2 动态链接的关键组件
  1. 全局偏移表(GOT):存储动态库函数的实际地址,位于.data节,可读写。用readelf -S可查看:

    readelf -S a.out | grep .got
    # 输出:[24] .got             PROGBITS         0000000000003fb8  00002fb8
    
  2. 过程链接表(PLT):为每个动态库函数提供一个 "跳板"。程序调用函数时,先跳转到 PLT,再通过 GOT 找到实际地址。PLT 的核心优化是延迟绑定—— 函数第一次调用时才查询实际地址并更新 GOT,后续调用直接使用 GOT 中的地址,减少加载时间。

5.2.3 动态链接的过程
  1. 加载动态库:程序启动时,动态链接器(ld-linux.so)加载程序依赖的动态库(如libmystdio.so、libc.so.6),并为每个库分配虚拟地址。
  2. 初始化 GOT 表:动态链接器根据库的虚拟地址和函数偏移,更新 GOT 表中对应函数的地址。
  3. 函数调用:程序调用动态库函数时,通过 PLT 跳转至 GOT 表中的实际地址,执行函数逻辑。

5.3 程序加载:从磁盘到内存的映射

操作系统加载 ELF 可执行程序的过程,本质是将文件中的段(Segment)映射到进程的虚拟地址空间,并初始化运行环境。

5.3.1 虚拟地址空间的作用

现代操作系统采用虚拟地址空间技术,为每个进程分配独立的 32 位或 64 位地址空间(如 64 位系统为0x0000000000000000到0xFFFFFFFFFFFFFFFF)。虚拟地址通过页表映射到物理内存,实现:

        内存隔离:进程无法访问其他进程的内存,提高安全性。

        地址独立:程序编译时无需考虑物理内存布局,只需使用虚拟地址。

5.3.2 ELF 加载的步骤
  1. 创建进程:操作系统为程序创建task_struct(进程控制块)和mm_struct(内存管理结构)。
  2. 解析 ELF 头:读取 ELF 文件的程序头表,确定需要加载的段(Segment)。
  3. 映射内存:将 ELF 文件中的段映射到进程虚拟地址空间的对应区域(如代码段映射到0x400000,数据段映射到0x600000)。
  4. 初始化 GOT/PLT:若为动态链接程序,动态链接器加载依赖库并更新 GOT 表。
  5. 跳转到入口地址:操作系统将 CPU 指令指针(EIP/RIP)指向 ELF 头中记录的入口地址(如0x400640),程序开始运行。

六、实战:使用外部库(ncurses)

除了自定义库,Linux 系统中还有大量成熟的第三方库。以ncurses(终端图形库)为例,讲解如何安装、编译和使用外部库。

6.1 安装 ncurses 库

        Ubuntu 系统:

sudo apt install -y libncurses-dev

CentOS 系统:

sudo yum install -y ncurses-devel

6.2 编写 ncurses 示例程序

以下代码实现一个终端进度条,使用 ncurses 库的窗口、颜色和光标控制功能:

#include <stdio.h>
#include <string.h>
#include <ncurses.h>
#include <unistd.h>

#define PROGRESS_BAR_WIDTH 30
#define BORDER_PADDING 2
#define WINDOW_WIDTH (PROGRESS_BAR_WIDTH + 2 * BORDER_PADDING + 2)
#define WINDOW_HEIGHT 5
#define PROGRESS_INCREMENT 3
#define DELAY 300000  // 300毫秒

int main() {
    initscr();          // 初始化ncurses
    start_color();      // 启用颜色
    // 定义颜色对:1(绿色前景,黑色背景)、2(红色前景,黑色背景)
    init_pair(1, COLOR_GREEN, COLOR_BLACK);
    init_pair(2, COLOR_RED, COLOR_BLACK);
    cbreak();           // 禁用行缓冲
    noecho();           // 禁用输入回显
    curs_set(FALSE);    // 隐藏光标

    // 获取终端大小,居中显示窗口
    int max_y, max_x;
    getmaxyx(stdscr, max_y, max_x);
    int start_y = (max_y - WINDOW_HEIGHT) / 2;
    int start_x = (max_x - WINDOW_WIDTH) / 2;

    // 创建窗口并绘制边框
    WINDOW *win = newwin(WINDOW_HEIGHT, WINDOW_WIDTH, start_y, start_x);
    box(win, 0, 0);
    wrefresh(win);

    // 模拟进度条更新
    int progress = 0;
    int max_progress = PROGRESS_BAR_WIDTH;
    while (progress <= max_progress) {
        werase(win);     // 清除窗口内容
        int completed = progress;
        int remaining = max_progress - progress;

        // 绘制已完成部分(绿色)
        attron(COLOR_PAIR(1));
        for (int i = 0; i < completed; i++) {
            mvwprintw(win, 1, BORDER_PADDING + 1 + i, "#");
        }
        attroff(COLOR_PAIR(1));

        // 绘制剩余部分(红色)
        attron(A_BOLD | COLOR_PAIR(2));
        for (int i = completed; i < max_progress; i++) {
            mvwprintw(win, 1, BORDER_PADDING + 1 + i, " ");
        }
        attroff(A_BOLD | COLOR_PAIR(2));

        // 显示百分比
        char percent_str[10];
        snprintf(percent_str, sizeof(percent_str), "%d%%", (progress * 100) / max_progress);
        int percent_x = (WINDOW_WIDTH - strlen(percent_str)) / 2;
        mvwprintw(win, WINDOW_HEIGHT - 1, percent_x, percent_str);

        wrefresh(win);   // 刷新窗口
        progress += PROGRESS_INCREMENT;
        usleep(DELAY);   // 延迟
    }

    // 清理资源
    delwin(win);
    endwin();
    return 0;
}

6.3 编译与运行

编译时需链接 ncurses 库(库名为ncurses,对应libncurses.so):

# 编译:-lncurses链接ncurses库
gcc progress_bar.c -o progress_bar -lncurses
# 运行
./progress_bar

运行后将在终端居中显示一个动态进度条,绿色部分表示已完成,红色部分表示剩余,直观展示 ncurses 库的终端图形能力。

六、总结:动静态库的选择与实践建议

在实际开发中,动静态库的选择需结合项目需求,以下是关键建议:

场景推荐库类型理由
嵌入式设备、独立工具静态库无依赖部署,适应资源受限环境
系统工具、大型应用动态库节省内存与磁盘空间,便于更新
库开发与调试动态库修改库代码后无需重新编译依赖程序
追求运行速度静态库无需运行时链接,加载速度快
oracle p6 破解版下载,Primavera P6项目管理软件 16~17 图文详细安装教程(附下载) Primavera P6 Professional项目管理软件结合了Oracle和Microsoft SQL Server关系数据库,是一款非常好用且功能强大的综合的项目管理软件(PPM) 解决方案,主要用于土建等方面的施工计划分析,具有进度时间安排与资源控制功能的多用户、多项目系统,支持多层项目分层结构、角色与技能导向的资源安排、记录实际数据、自定义视图以及自定义数据,本文主要为大家图文详细介绍... 阅读详情

相关推荐

2025年最新Cesium学习示例:Cesium-Examples

2025年最新Cesium学习示例:Cesium-Examples

2403_88103571的博客 1009

C/C++常见gcc编译链接错误解决方法

除非明确说明,本文内容仅针对x86/x86_64的Linux开发环境,有朋友说baidu不到,开个贴记录一下(加粗字体是关键词): 用“-Wl,-Bstatic”指定链接静态库,使用“-Wl,-Bdynamic”指定链接共享库,使用示例: -Wl,-Bstatic -lmysqlclient_r -lssl -lcrypto -Wl,-Bdynamic...

weixin_33962621的博客 5268

3-RRR并联机器人结构详解:从运动学到奇异点分析(附MATLAB仿真代码)

本文详细解析了3-RRR并联机器人的结构设计、运动学建模及奇异点分析,并提供了MATLAB仿真代码。通过对称性设计和可分析性,3-RRR结构成为教学与研究的理想对象。文章从基础杆件参数设置到奇异位形的实时捕捉,深入探讨了机构运动的数学本质,并分享了仿真调试中的实用技巧,助力工业自动化和精密控制应用。

sunny的博客 342

Linux 动静态库的制作,使用和加载

Linux 动静态库的制作,使用和加载

Wzs040810的博客 2691

MySQL安装配置教程(超级详细)

一、 下载MySQL Mysql官网下载地址:MySQL :: Download MySQL Installer (Archived Versions) 1. 选择要安装的版本,本篇文章选择的是5.7.31版本,点击Download下载 正在上传…重新上传取消 二、 安装MySQL 1. 选择设置类型双击运行mysql-installer-community-5.7.31.0.msi 这里选择是自定义安装,所以直接选择“Custom”,点击“Next” “Developer Default”是

m0_67322837的博客 5万+

51单片机也能玩转GC9A01彩屏?超详细移植指南与性能优化技巧

本文详细介绍了如何在51单片机上高效驱动GC9A01彩屏,包括硬件连接优化、SPI模拟驱动、内存管理策略及高级刷新技术。通过分段缓冲、颜色压缩和差异化刷新等技巧,显著提升显示性能,使51单片机也能流畅运行240x240分辨率的彩色TFT屏幕。

hp777的博客 189

深入理解 Linux 动静态库:制作、原理与加载机制

本文深入解析Linux系统中动静态库的开发与应用。从基础概念入手,介绍了静态库(.a)和动态库(.so)的制作方法、使用场景及区别。重点剖析了ELF文件格式的组成结构,包括ELF头、程序头表、节头表等核心组件。通过工具链(readelf、objdump等)演示了如何查看ELF文件信息。最后详细阐述了程序的静态链接与动态链接机制,包括动态库加载的GOT/PLT技术、延迟绑定等底层原理,帮助开发者全面理解库在Linux系统中的工作方式。

fantasy5_5的博客 981

2006NOIP普及组真题 4. 数列

从上述推理中,我们发现要输出的幂次和中的第 N 项(也就是幂次和中的序号N),对应的二进制位数和幂次和对应的二进制位数相同。当 k=3 时,k的幂次为1, 3, 9, 27, 81…,即第0位,第2位均为1,转成 k 进制(k=3)时。,即第2位,第3位均为1,转成 k 进制(k=3)时。转成 k 进制(k=3)时的幂次和为。,即第0位,第1位,第2位均为1,(即第0位,第1位,第2位均为1)N=12时,12的二进制是。(即第0位,第2位均为1)(即第2位,第3位均为1)结论:这道题就变成了。

weixin_40252159的博客 1513

[Linux]:动静态库

想深入了解 Linux 中的动静态库吗?本文将为你详细解读它们的原理、使用方法及打包方式,助你轻松掌握这一重要知识,提升编程技能,快来探索吧!

Bettysweetyaaa的博客 2128

【LIN总线测试】——LIN主节点物理层测试

LIN总线是基于UART/SCI(通用异步收发器/串行接口)的低成本串行通讯协议。其目标定位于车身网络模块节点间的低端通信,主要用于智能传感器和执行器的串行通信,而这正是CAN总线的带宽和功能所不要求的部分。本章节主要介绍LIN主节点物理层如何测试?

测试领域技术分享 5529

下采样新突破!ADown模块让YOLOv11多尺度特征提取更精准

ADown 凭借可编程梯度信息与多分支特征聚合的创新设计,打破了传统下采样在特征保留上的固有局限。本教程从原理到代码实现,再到工业场景适配,完整呈现了其在 YOLOv11 中的集成路径。只需简单新增模块脚本并修改配置文件,你的目标检测模型就能在多尺度特征捕捉能力上实现跨越式提升——无论是学术研究中的小目标检测突破,还是工业场景下的复杂多尺度任务落地,ADown 都能成为你攻克下采样瓶颈的利器。现在就动手尝试,让你的检测模型在下一代下采样技术的创新中再上一个台阶吧。

know_F0727的博客 524

【Linux学习笔记】深入理解ELF和动静态库加载原理

本文深入解析了ELF文件的结构和加载原理。ELF文件可分为四种类型:可重定位文件、可执行文件、共享目标文件和内核转储文件。ELF由四部分组成:ELF头、程序头表、节头表和节。重点介绍了ELF从编译链接到加载执行的完整过程,包括.section合并为Segment的原则,以及如何通过程序头表确定加载方式。文章还提供了查看ELF文件结构的实用命令(readelf -S/-l),帮助开发者理解可执行程序的内存布局。通过对ELF文件加载机制的剖析,读者可以更深入地掌握Linux程序运行的底层原理。

大白的编程日记. 1332

MTK(camera篇)Camera整体点亮

本文介绍了在MTK平台上添加新Camera Sensor的驱动开发流程。主要内容包括:1)MTK Camera采用HAL3架构,驱动层主要负责sensor电源控制和寄存器操作;2)详细说明了添加新sensor需要在多个文件中进行的修改,包括设备树配置、内核头文件、驱动列表、电源序列等;3)特别指出需要配置I2C地址表,并导入tuning文件和metadata文件以完善ISP处理流程。文章提供了完整的文件修改清单,涵盖了从内核层到HAL层的完整开发过程,为MTK平台Camera Sensor驱动开发提供了具体

weixin_49303682的博客 361

【Linux系统】代码星辰里的积木与流萤:动静态库的编程诗篇

动静态库制作与使用指南 本文将详细介绍静态库和动态库的制作、生成、发布及使用方法。静态库通过ar工具打包.o文件生成.a文件,使用Makefile自动化构建过程;动态库则需-fPIC编译选项生成位置无关代码,再用-shared链接成.so文件。文中提供完整代码示例和Makefile配置,并深入讲解库的发布方式(头文件与库文件分离管理)、使用技巧(-I/-L/-l参数设置)以及系统安装方法(软链接创建)。通过对比动静态库特性,帮助开发者掌握两种库的适用场景及实践要点。 关键词:静态库、动态库、Makefile

17的博客 1万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

【深入理解】动静态库的制作、使用与加载原理(附详细操作指南)

本文介绍了编程中两种库类型:静态库和动态库。静态库在编译时嵌入可执行文件,生成较大但独立的程序;动态库在运行时加载,实现多程序共享。文章详细讲解了两种库的制作使用方式、ELF文件格式结构,以及链接加载过程。通过对比分析,静态库适合独立部署,动态库利于资源共享和更新。还介绍了readelf、objdump等工具用于分析库文件结构。理解这些概念能帮助开发者选择适当的库类型,提升程序效率和维护性。

m0_67804957的博客 761

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

【Linux】基础IO-文件系统和动静态库

而 A 呢不想暴露源码,担心老师发现,然后两个人一块寄了(老师不会主动去检查源码,只要程序能跑就行),所以就把 .c 文件编译成了 .o 文件发给了 B,这样 B 只需要写一个 main.c 文件,调用这些 .o 文件中的接口最后一起编译就可以了,而且不会暴露源码。当然,整个硬盘的空间是非常大的,而一个块的大小也不过是 4 KB,所以如果想把一整个硬盘管理好,最好将其分为几个区,只要管理好一个分区,那么经验就可以套用到其他分区。啊,我们访问目录的内容,也是需要找到目录的 inode,进而访问目录内容。

Hello World! 1302

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Linux——基础IO(2)及动静态库多种方式使用及制作

有关上篇文章 基础IO(1) 问题遗留解答及总结:1. 如下述代码,重定向后,使用C标准库函数写入后,使用系统调用接口close关闭文件后,运行后,其重定向文件内部没有数据!而在close之前使用C标准库提供的fflush函数后,文件内部便有了数据,作何解释?close(1);return 1;close(fd);return 0;

IfYouHave的博客 596

【Linux】磁盘结构&&文件系统&&软硬链接&&动静态库

静态库 (.a):程序在编译链接的时候把库的代码链接 (拷贝) 到可执行文件中,程序运行的时候将不再需要静态库。动态库 (.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

t5y22的博客 1280

【Linux】文件查找、软硬链接、动静态库

本博客深入探讨了Linux文件系统、IO操作、软硬链接、动态库与静态库等内容。从文件查找机制到软硬链接的特征与应用,再到动态库与静态库的制作、使用及区别,均有详细讲解。通过实例展示了如何创建和使用软硬链接,以及如何将代码编译成.o文件,再进一步打包成静态库或动态库,还介绍了链接时的注意事项和库的加载机制。内容丰富实用,适合Linux学习者和开发者参考,能帮助读者更好地理解和运用Linux系统底层知识。

2303_77756141的博客 979

【Linux系统编程】:动态库和静态库

静态库动态库的制作和使用

m0_66182473的博客 1609

Linux系统--文件系统--动静态库

库(Library)本质上是一种可执行代码的二进制形式,它可以被操作系统载入内存执行。举个不严谨的例子,我们写的代码像是一辆含有说明书的没有车轮或者轮胎的赛车,说明书中清楚的说明了我们的车这场比赛需要使用到哪种轮胎,是全热熔的还是半热熔的,是软胎还是硬胎,还是雨胎……,库就是一个巨大的轮胎供应商,比如倍耐力,其中啥轮胎都有……如果想让我们写的程序(赛车🏎)真正跑起来,我们需要将轮胎供应商中合适我们赛车的轮胎装上。库就是一个轮胎供应商,需要使用的时候,我们就可以直接拿来使用。从而省去我们自己造轮胎的时间。其

LXdian_LX的博客 1198

Linux基础IO【软硬链接与动静态库】

假设你下载了一款游戏,你是否会跑到游戏所在目录中双击.exe打开游戏?答案是不会,大多数人都会通过桌面的快捷方式直接打开文件,而这个快捷方式实际就是对.exe的软链接文件;当你在游戏中加载地图、道具等资源时,这些数据是存在.exe文件中的吗?答案是当然不是,这些资源文件都以库的方式与.exe位于同一目录中,通常为动态库,在Windows中后缀为dll,那么这些神奇的辅助文件是如何产生的?本文将带你一起揭晓

北 海的博客 8630

【Linux】文件系统及动静态库

以上就是今天要讲的内容,本文仅仅是简单介绍了Linux文件系统及动静态库的制作和使用。

m0_62179366的博客 562

深入理解Linux动静态库原理与应用

实际操作时,我发现其内置的Linux环境特别适合库开发实验。不需要配置复杂的交叉编译环境,直接在线就能完成从代码编写到部署测试的全流程。对于需要演示不同链接方式效果的项目,平台的一键部署功能可以快速生成可访问的演示页面,比本地搭建环境方便很多。动态库在运行时才加载,通过内存共享机制节省空间,但依赖环境配置。编译时需指定-I(头文件路径)和-l(库名)参数。通过PLT(过程链接表)延迟绑定提升效率。系统级开发常混合使用两种库类型。可通过ldd命令检查依赖关系。程序头表决定加载方式。

ThunderstormDragon65的博客 320

深入理解 Linux 文件系统与动静态库

我们可以通过配置/etc/ld.so.conf.d/的方式解决该问题,/etc/ld.so.conf.d/路径下存放的全部都是以.conf为后缀的配置文件,而这些配置文件当中存放的都是路径,系统会自动在/etc/ld.so.conf.d/路径下找所有配置文件里面的路径,之后就会在每个路径下查找你所需要的库。其实无论是动态库还是静态库,都是把一堆源文件编译处理出的.o文件(二进制文件)整理在一起,在加上这些源文件对应的头文件,就是一个完整的库了,这样既隐藏了库的源代码,也能让其他开发者使用这个库的功能。

weixin_73567058的博客 1639

Linux的文件系统、软硬链接、动静态库

前要:本次我想给您带来关于IO和文件的知识,而文件在本系列中分为内存上的文件和磁盘上的文件。

limou3434的博客 1050
上一篇: 深入理解 Linux Ext 系列文件系统:从磁盘物理结构到软硬链接
下一篇: 深入理解 Linux 进程间通信:从原理到实战
cpparf
博客等级 码龄2年 48粉丝 65原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值