基于 GD32F303ZET6 苹果派开发板
简介
终端控件那一章引入自定义的动态内存管理组件时,忘记配置 PNG 驱动的动态内存了,最近才发现的,就挺烦。这导致了 PNG 驱动使用的动态内存管理方案一直都是 C 语言默认的,即 malloc 、realloc 和 free 函数。这几个函数使用的堆区在启动文件中定义。在终端控件之前,启动文件中的堆区开的比较大,malloc 函数能够成功申请到比较大的、且连续的动态内存。可是到后边逐渐发现这个堆区开的实在是太大了,很容易导致内部 SRAM 不够用,多定义几个控件内存就没了。于是就引入了自定义的内存管理组件,并将启动文件中的堆区定义的很小。这就导致了 PNG 模块解码时,通过 malloc 函数无法申请到足够多的动态内存,导致解码失败。
本章中就是为了给 PNG 驱动配置动态内存分配,顺便了解一下 LodePNG 如何配置各个功能。
配置宏定义
LodePNG 通过宏定义配置各项功能,动态内存配置相关的宏定义如下所示。LodePNG 每个配置宏都会有详细的说明,下面这段代码的意思是:如果用户未定义 LODEPNG_NO_COMPILE_ALLOCATORS 宏,那么 LodePNG 将使用 C 语言默认的动态内存分配方案,即 free、malloc 和 realloc;如果用户定义了该宏,那么用户就需要实现 lodepng_free、lodepng_malloc 和 lodepng_realloc 三个函数,来为 LodePNG 释放、申请和重新申请动态内存。
/*Compile the default allocators (C's free, malloc and realloc). If you disable this,
you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your
source files with custom allocators.*/
#ifndef LODEPNG_NO_COMPILE_ALLOCATORS
/*pass -DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler to disable the built-in ones,
or comment out LODEPNG_COMPILE_ALLOCATORS below*/
#define LODEPNG_COMPILE_ALLOCATORS
#endif
综上可知,我们只需要在上述段代码之前定义 LODEPNG_NO_COMPILE_ALLOCATORS 宏,即可取消 LodePNG 默认的动态内存方案,如下所示。
//禁止使用 C 语言自带的内存分配函数
#define LODEPNG_NO_COMPILE_ALLOCATORS
LodePNG 默认内存管理方案分析
在 LodePNG 源文件中,动态内存的申请和释放如下所示。一旦用户定义了 LODEPNG_NO_COMPILE_ALLOCATORS 宏,根据上述的代码,LODEPNG_COMPILE_ALLOCATORS 宏将变成未定义,所以 lodepng_malloc 、lodepng_realloc 和 lodepng_free 三个函数将会由定义转变成声明,所以用户需要在自行定义这三个函数,否则编译器会报错。
有些同学可能会为了方便,直接修改 LodePNG 源码中 lodepng_malloc 、lodepng_realloc 和 lodepng_free,这也是可以的,但是为了方便移植到其它平台,保证源码的原汁原味,在这里还是推荐自己实现这三个函数。
#ifdef LODEPNG_COMPILE_ALLOCATORS
static void* lodepng_malloc(size_t size) {
#ifdef LODEPNG_MAX_ALLOC
if(size > LODEPNG_MAX_ALLOC) return 0;
#endif
return malloc(size);
}
/* NOTE: when realloc returns NULL, it leaves the original memory untouched */
static void* lodepng_realloc(void* ptr, size_t new_size) {
#ifdef LODEPNG_MAX_ALLOC
if(new_size > LODEPNG_MAX_ALLOC) return 0;
#endif
return realloc(ptr, new_size);
}
static void lodepng_free(void* ptr) {
free(ptr);
}
#else /*LODEPNG_COMPILE_ALLOCATORS*/
/* TODO: support giving additional void* payload to the custom allocators */
void* lodepng_malloc(size_t size);
void* lodepng_realloc(void* ptr, size_t new_size);
void lodepng_free(void* ptr);
#endif /*LODEPNG_COMPILE_ALLOCATORS*/
为 LodePNG 分配动态内存
在 lodepng.h 中定义了 LODEPNG_NO_COMPILE_ALLOCATORS 宏之后,在 PNG.c 或工程中任意一个地方添加如下所示代码。在这里仿照了 LodePNG 源码中的格式,使用了预编译命令来控制这几个函数是否要被编译。
/*********************************************************************************************************
* 函数名称: lodepng_malloc
* 函数功能: lodepng 动态内存分配函数
* 输入参数: size:需要申请的动态内存大小(字节)
* 输出参数: void
* 返 回 值: 申请到的动态内存的首地址
* 创建日期: 2023年02月22日
* 注 意:
*********************************************************************************************************/
#ifdef LODEPNG_NO_COMPILE_ALLOCATORS
void* lodepng_malloc(size_t size)
{
return MyMalloc(SRAMEX, size);
}
#endif
/*********************************************************************************************************
* 函数名称: lodepng_realloc
* 函数功能: lodepng 内存重新分配函数
* 输入参数: ptr:旧动态内存的首地址,new_size:新动态内存的大小
* 输出参数: void
* 返 回 值: 申请到的动态内存的首地址
* 创建日期: 2023年02月22日
* 注 意:
*********************************************************************************************************/
#ifdef LODEPNG_NO_COMPILE_ALLOCATORS
void* lodepng_realloc(void* ptr, size_t new_size)
{
return MyRealloc(SRAMEX, ptr, new_size);
}
#endif
/*********************************************************************************************************
* 函数名称: DrawPNG
* 函数功能: lodepng 内存释放函数
* 输入参数: ptr:动态内存首地址
* 输出参数: void
* 返 回 值: void
* 创建日期: 2023年02月22日
* 注 意:
*********************************************************************************************************/
#ifdef LODEPNG_NO_COMPILE_ALLOCATORS
void lodepng_free(void* ptr)
{
MyFree(ptr);
}
#endif
修改 PNG 绘制函数
现在 PNG 显示模块使用的动态内存是由自定义的内存管理机制提供的,不是由 C 语言 malloc 函数分配而来,不能用 free 函数释放,所以 PNG 绘制函数中,最后的内存释放需要稍加修改,如下所示。
void DrawPNG(unsigned char* image, unsigned int x, unsigned int y, unsigned int size)
{
//解码 PNG 图片
...
//释放动态内存
#ifdef LODEPNG_NO_COMPILE_ALLOCATORS
MyFree(output);
#else
free(output);
#endif
}
实验结果
实验结果如下所示。
-为-PNG-显示分配动态内存-实验结果-20230304-1024x768.jpg)
源码
本章节中的源码请参考《单片机 GUI 设计(零)- 大纲》