在讲如何实现之前,我们首先要了解什么是 热重载

热重载 C 这是一篇挺好的文章,可以帮助大家了解相关概念(尤其是动态链接部分,本文并不打算讲解这部分,本文可以看成是对这篇文章例子的补充)

按照我的理解,热重载 这个名字其实就能够解释了,就是 重新载入 '热' 的部分重新载入 好理解,那什么是 呢?其实我也不太明白,它应该是一个抽象的概念,用来表示那些 频繁引用 的部分

比如你的一个 switch 语句,其中一个 case 标签经常命中,那么他就是

按照字面意思理解了之后,他有什么用呢

其中一个重要的作用就是 立即反映,比如说你正在调试一个c程序,然后修改了源代码中的某个地方,ok,重新编译,重新运行,这样一来一回其实还挺烦的

那如果你将某个 频繁更改 的代码部分看作是一个 ,一个 的部分,然后使用 热重载 技术,这样你就能够在 程序不重启的前提下,即时观察到更改带来的效果

接下来,我们来一个简单的例子,带大家体验一下

本次实验基于以下环境:

  • 操作系统:Ubuntu22.04
  • 编译器:gcc 11.4.0

首先上场的是,作为 的部分的代码,也就是我们将要 频繁修改 的代码部分

// counter.c

#include <stdio.h>

void counter(void)
{
    int end = 10;
    printf("end=%d -> ", end);
    for (int i = 0; i < end; i++)
        printf("%d ", i);
    printf("\n");
}

这是一个 counter,就是打印 [0, end) 的数字,然后我们将要修改 end 的值,并希望能够 即时 看到打印数字的变化

这部分代码是 加载模块卸载模块,主要使用了 动态链接 的知识,不了解的同学,还请阅读开头推荐的文章,我这里就不细讲了

原理就是,先 卸载旧的模块(如果有的话),然后 system("make") 执行的时候,将代码 编译成动态库,这样能够保持 的部分是最新的,最后再 加载新的模块

// demo.c

static void unload_module(void *handle)
{
    dlclose(handle);
}

static void *load_module(const char *path)
{
    static void *handle = NULL;

    // unload the old module
    if (handle != NULL) unload_module(handle);

    system("make");
    handle = dlopen(path, RTLD_LAZY);
    if (handle == NULL) {
        fprintf(stderr, "dlopen error: %s\n", dlerror());
        return NULL;
    }

    return handle;
}
## Makefile

libcounter.so: counter.c
	gcc -shared -fPIC -o libcounter.so counter.c

最后是主程序部分,首先使用fgetc来阻塞程序,方便我们 “暂停” 修改代码,然后就是 加载模块,接着是 加载模块中的符号,也就是counter函数,最后是 执行函数 counter()

// demo.c

typedef void (*counter_func)(void);

int main(void)
{
    char buffer[128];
    while (1) {
        fgetc(stdin);

        void *handle = load_module("./libcounter.so");
        counter_func counter = dlsym(handle, "counter");
        if (counter == NULL) {
            fprintf(stderr, "dlsym error: %s\n", dlerror());
            unload_module(handle);
            return 1;
        }

        counter();
    }

    return 0;
}

到这里我们已经讲解了代码的大致流程,接下来看看效果吧

首先这里是编译主程序,然后给大家先解释下这个图片,上面窗口是我们的 counter.c 代码,我们会修改 int end = 10; 这一行,下面是我们的 终端打印的结果会呈现在这里

1

开始执行,let's go

  • int end = 10;

1

  • int end = 20;

2

  • int end = 1;

3

到这里,希望你对 如何在c中实现热重载技术 有了一定的想法,然后就去不断实践它吧

 posted on 2025-05-12 11:28  Dylaris  阅读(91)  评论(0)    收藏  举报