C++与Lua交互内存分配详解

 更新时间:2023年11月17日 10:29:14   作者:江澎涌  
C/C++ 与 Lua 的交互是通过 lua_State 这一句柄进行交互,我们常规的创建都是通过 luaL_newstate 这一辅助函数,这篇文章主要给大家详细介绍了C++与Lua交互内存分配,文中有相关的代码示例供大家参考,需要的朋友可以参考下

一、lua_State 创建

C/C++ 与 Lua 的交互是通过 lua_State 这一句柄进行交互。我们常规的创建都是通过 luaL_newstate 这一辅助函数,他的源码实现如下:

LUALIB_API lua_State *luaL_newstate (void) {
  lua_State *L = lua_newstate(l_alloc, NULL);
  if (l_likely(L)) {
    lua_atpanic(L, &panic);
    lua_setwarnf(L, warnfoff, L);  /* default is warnings off */
  }
  return L;
}

通过源码可以知道,真正的创建是通过 lua_newstate 函数

LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud)

描述

函数创建并返回 lua_State 类型的指针,后续通过这一指针和 Lua 进行交互。这期间所有的内存分配和释放都会由参数 f 函数进行完成,包括该函数返回的 lua_State

参数

  • 参数 f :分配函数
  • 参数 ud :自定义用户数据,会携带进入 f 函数

返回值:

lua_State 的指针

二、分配函数

Lua 中默认的分配函数使用了 C 语言标准函数库的标准函数 malloc-realloc-free 进行内存的管理,以下便是 Lua 默认分配函数。

static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
  (void)ud; (void)osize;  /* not used */
  if (nsize == 0) {
    free(ptr);
    return NULL;
  }
  else
    return realloc(ptr, nsize);
}

我们可以自行定义,只需遵循 lua_Alloc 格式,通过 lua_newstate 函数或 lua_setallocf 函数设置即可生效

typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);

参数:

  • 参数 ud: lua_newstate 的第二个参数便会作为该参数,并且是每次调用该分配函数都会携带。
  • 参数 ptr: 正要被分配、或是重新分配、或者是要被释放的块地址。
  • 参数 osize: 原始块的大小。
  • 参数 nsize: 需要申请的块大小。

返回值:

  • 如果需要创建新的内存块,则将创建的内存块指针返回。
  • 如果不需要创建内存块,则返回 NULL。

值得注意:

从分配函数的参数和返回值,已经知道了这一函数的职责:释放原始块和创建新的块并返回。所以会涉及以下一些小细节:

  • 当 ptr 是 NULL ,则原始内存块大小肯定是零,所以 Lua 使用 osize 存放某些调试信息。
  • 当 ptr 是 NULL ,则分配函数必须分配并返回 nsize 指定大小的块。如果无法分配相应的块,则返回 NULL 。如果此时 nsize 为 零 则返回 NULL 。
  • 当 nsize 为零时,分配函数必须释放 ptr 指向的块并返回 NULL 。
  • 如果 ptr 不是 NULL 并且 nsize 不为零,则可以使用 realloc 进行重新分配块并返回(地址可能和原来一样,也可能不一样)。和第二点一样,如果出错了则返回 NULL 。
  • Lua 会假定分配函数在块的新尺寸( nsize )小于或等于旧尺寸( osize )时不会失败。

三、获取当前的内存分配函数

通过 lua_getallocf 获取 Lua State 当前的内存分配函数

LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);

参数:

  • 参数 L: lua_State 指针。
  • 参数 ud: 会把当前设置的自定义用户数据设置给这一参数。

返回值:

Lua 当前使用的内存分配函数

四、设置内存分配函数

通过 lua_setallocf 设置新的内存分配函数

LUA_API void      (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);

参数:

  • 参数 L: lua_State 指针。
  • 参数 f: 需要设置新的内存分配函数。
  • 参数 ud: 自定义用户数据。

五、举个例子

下面的代码主要验证了三个步骤:

  • 创建 lua_State 时传入自己的内存分配函数和自定义用户数据,函数中会打印所有的参数。
  • 获取当前的分配函数。
  • 替换当前的分配函数,最后关闭 lua_State 的时候会打印日志。
static void *alloc(void *ud, void *ptr, size_t osize, size_t nsize) {
    const char *udContent = *(const char **) ud;
    std::cout << "ud: " << udContent << "; *ptr: " << ptr << "; osize: " << osize << "; nsize: " << nsize << std::endl;
    if (nsize == 0) {
        free(ptr);
        return nullptr;
    } else
        return realloc(ptr, nsize);
}

static void *newalloc(void *ud, void *ptr, size_t osize, size_t nsize) {
    const char *udContent = *(const char **) ud;
    std::cout << "新的分配函数 " << "ud: " << udContent << "; *ptr: " << ptr << "; osize: " << osize << "; nsize: " << nsize << std::endl;
    if (nsize == 0) {
        free(ptr);
        return nullptr;
    } else
        return realloc(ptr, nsize);
}

void allocationFunction() {
    // 常规的创建 lua_State
//    auto L = luaL_newstate();

    printf("------------- 自定义内存分配函数 -------------\n");
    // 自定义内存分配数据
    auto ud = "ud test message.";
    auto L = lua_newstate(alloc, &ud);

    printf("------------- 获取 Lua 当前的内存分配函数 -------------\n");
    // lua_getallocf 第二个参数会返回之前设置的 自定义内存分配数据
    void *userData = nullptr;
    lua_Alloc allocFunc = lua_getallocf(L, &userData);
    const char *udContent = *(const char **) userData;
    std::cout << &allocFunc << " " << udContent << std::endl;

    printf("------------- 设置 Lua 的内存分配函数 -------------\n");
    auto nud = "new ud test message.";
    lua_setallocf(L, newalloc, &nud);

    std::cout << "关闭 lua_State " << std::endl;
    lua_close(L);
}

运行之后的日志

------------- 自定义内存分配函数 -------------
ud: ud test message.; *ptr: 0x0; osize: 8; nsize: 1624
...... 省略很多内存分配打印日志
ud: ud test message.; *ptr: 0x0; osize: 4; nsize: 30
------------- 获取 Lua 当前的内存分配函数 -------------
0x7ff7b7775f80 ud test message.
------------- 设置 Lua 的内存分配函数 -------------
关闭 lua_State 
新的分配函数 ud: new ud test message.; *ptr: 0x0; osize: 0; nsize: 0
...... 省略很多内存分配打印日志
新的分配函数 ud: new ud test message.; *ptr: 0x7fd3ef80c400; osize: 1624; nsize: 0

以上就是C++与Lua交互内存分配详解的详细内容,更多关于C++与Lua交互内存分配的资料请关注脚本之家其它相关文章!

相关文章

  • C语言游戏必备:光标定位与颜色设置的实现方法

    C语言游戏必备:光标定位与颜色设置的实现方法

    本篇文章是对c语言中光标定位与颜色设置的方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 关于C语言和命令行之间的交互问题

    关于C语言和命令行之间的交互问题

    这篇文章主要介绍了C语言和命令行之间的交互,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-07-07
  • c++选择排序详解

    c++选择排序详解

    选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从无序组的数据元素中选出最小(或最大)的一个元素,存放在无序组的起始位置,无序组元素减少,有序组元素增加,直到全部待排序的数据元素排完。
    2017-05-05
  • 关于vector迭代器失效的几种情况总结

    关于vector迭代器失效的几种情况总结

    下面小编就为大家带来一篇关于vector迭代器失效的几种情况总结。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • c++并查集优化(基于size和rank)

    c++并查集优化(基于size和rank)

    这篇文章主要介绍了c++并查集优化(基于size和rank),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • c++中priority_queue模拟的实现

    c++中priority_queue模拟的实现

    priority_queue是C++标准库中的一个容器适配器,用于实现优先队列的数据结构,本文主要介绍了c++中priority_queue模拟的实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-09-09
  • C语言之直接插入排序算法的方法

    C语言之直接插入排序算法的方法

    这篇文章主要为大家介绍了C语言直接插入排序算法的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • C语言实现扫雷游戏(含注释详解)

    C语言实现扫雷游戏(含注释详解)

    这篇文章主要为大家详细介绍了C语言实现扫雷游戏,含注释,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • C++音乐播放按钮的封装过程详解

    C++音乐播放按钮的封装过程详解

    此篇文章用于记录学习C++封装音乐播放按钮,封装将对象的属性和行为作为一个整体,表现生活中的事物、将属性和行为加以权限控制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • 一文掌握C++ const与constexpr及区别

    一文掌握C++ const与constexpr及区别

    C++ 11标准中,const 用于为修饰的变量添加“只读”属性而 constexpr关键字则用于指明其后是一个常量,编译器在编译程序时可以顺带将其结果计算出来,而无需等到程序运行阶段,这样的优化极大地提高了程序的执行效率,本文重点介绍C++ const与constexpr区别介绍,一起看看吧
    2024-02-02

最新评论