You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌入式系统中C语言模拟类的多实例内存优化方案问询

C语言模拟类模型的嵌入式内存优化方案

问题背景

我用C语言模拟类模型,通过struct表示类,结构体内部用函数指针定义方法,代码实现如下:

ClassName.h

typedef struct struct_ClassName ClassName;

struct ClassName
{
    char a;
    char b;
    char c;
    void (*method1)(ClassName*, char);
    void (*method2)(ClassName*, char);
    // ...
    void (*methodN)(ClassName*, char);
};

void initClassName(ClassName*);

ClassName.c

#include "ClassName.h"

static void method1(ClassName *this_c, char c);
static void method2(ClassName *this_c, char c);
// ...
static void methodN(ClassName *this_c, char c);

void initClassName(ClassName *this_c)
{
    this_c->method1 = &method1;
    this_c->method2 = &method2;
    // ...
    this_c->methodN = &methodN;
}

void method1(ClassName *this_c, char c)
{
    // 实现逻辑
}

void method2(ClassName *this_c, char c)
{
    // 实现逻辑
}

// ...

void methodN(ClassName *this_c, char c)
{
    // 实现逻辑
}

当前代码运行正常,但我定义了一个包含200个对象的数组:

ClassName objects[200];

for(int i = 0; i < 200; i++)
{
    initClassName(&objects[i]);
}

由于结构体包含多个函数指针,每个对象都要存储这些指针,导致数组整体内存占用过高。我需要在嵌入式系统中优化内存使用,同时保留类模型的模拟方式,不能使用C++,也不想把方法完全定义在结构体外部。


优化方案:共享虚表(vtable)

核心思路是把所有方法的函数指针提取到一个单独的虚表结构体中,每个类只维护一份全局虚表实例,所有对象只需存储一个指向该虚表的指针,而非每个对象都复制所有函数指针。这种方式既能保留类模型的封装性,又能大幅减少重复内存开销。

1. 修改头文件(ClassName.h)

// 先定义虚表结构体,存放所有方法的函数指针
typedef struct ClassNameVTable ClassNameVTable;

struct ClassNameVTable
{
    void (*method1)(ClassName*, char);
    void (*method2)(ClassName*, char);
    // ...
    void (*methodN)(ClassName*, char);
};

// 类结构体仅保留数据成员和虚表指针
typedef struct struct_ClassName ClassName;

struct struct_ClassName
{
    char a;
    char b;
    char c;
    ClassNameVTable* vtable; // 指向共享的全局虚表
};

// 初始化函数声明
void initClassName(ClassName*);
// 暴露全局虚表(也可通过内部静态变量封装,按需选择)
extern const ClassNameVTable ClassName_vtable;

2. 修改实现文件(ClassName.c)

#include "ClassName.h"

// 静态实现各个方法,保持封装性
static void method1(ClassName *this_c, char c)
{
    // 具体实现逻辑
}

static void method2(ClassName *this_c, char c)
{
    // 具体实现逻辑
}

// ...

static void methodN(ClassName *this_c, char c)
{
    // 具体实现逻辑
}

// 定义全局唯一的虚表实例,用const修饰可放入ROM,节省RAM
const ClassNameVTable ClassName_vtable = {
    .method1 = method1,
    .method2 = method2,
    // ...
    .methodN = methodN
};

void initClassName(ClassName *this_c)
{
    // 仅需给对象的虚表指针赋值,无需逐个设置函数指针
    this_c->vtable = &ClassName_vtable;
    // 按需初始化数据成员
    // this_c->a = 0;
}

3. 方法调用方式

调用对象方法时,通过虚表指针间接访问:

ClassName obj;
initClassName(&obj);
// 调用method1
obj.vtable->method1(&obj, 'x');

优化效果

以32位系统为例(每个指针占4字节),假设类有10个方法:

  • 原方案:每个对象占用 3 + 4*10 = 43 字节,200个对象总占用 200*43 = 8600 字节
  • 优化方案:每个对象占用 3 + 4 = 7 字节,加上虚表本身的 4*10 = 40 字节,总占用 200*7 + 40 = 1440 字节

内存占用仅为原方案的16.7%,方法数量越多,节省效果越显著。

嵌入式场景额外优化

  • 将虚表声明为const后,编译器会将其放置在**ROM(程序存储空间)**而非RAM中,进一步节省嵌入式系统中宝贵的RAM资源。
  • 如果不需要多态支持(即不会有子类重写方法),可以直接通过全局虚表调用方法,甚至省略对象内的虚表指针,但这会损失类模型的封装性,需根据实际需求权衡。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 10:24:05