目录
1. 简介
2. 示例解析
2.1 源码解释
2.2 malloc 分析
2.3 替代方案分析
3. 总结
1. 简介
Vitis HLS 也不支持动态创建或删除 C/C++ 对象(用于综合)。
本文探究如何在C/C++代码中避免使用显式的malloc函数来分配内存。在硬件设计和FPGA开发中,避免动态内存分配是一个常见的实践。
通过一个例子,了解 malloc 被用于动态分配内存,但是在 USE_MALLOC 未定义的情况下,代码使用了栈上的局部变量来代替。
2. 示例解析
2.1 源码解释
#include <stdlib.h>
long long example(int din[32], int width) {
#ifdef USE_MALLOC
long long *out_accum = malloc(sizeof(long long));
int *array_local = malloc(64 * sizeof(int));
#else
long long _out_accum;
long long *out_accum = &_out_accum;
int _array_local[64];
int *array_local = &_array_local[0];
#endif
int i, j;
LOOP_SHIFT:
for (i = 0; i < 31; i++) {
if (i < width)
*(array_local + i) = din[i];
else
*(array_local + i) = din[i] >> 2;
}
*out_accum = 0;
LOOP_ACCUM:
for (j = 0; j < 31; j++) {
*out_accum += *(array_local + j);
}
return *out_accum;
}
函数 example 接受一个整数数组 din 和一个选择宽度 width 作为参数。它通过两个循环处理数组:第一个循环 LOOP_SHIFT 根据 width 值对数组元素进行移位操作,第二个循环 LOOP_ACCUM 累加处理后的数组元素到 out_accum。最终,函数返回累加的结果。
2.2 malloc 分析
首先了解 malloc 的用途:
long long *out_accum = malloc(sizeof(long long));
这句代码声明了一个指向long long类型的指针out_accum,并使用malloc函数为它分配了足够存储一个long long类型数据的内存空间。sizeof(long long)是计算long long类型数据大小的操作,确保分配的内存正好可以存放一个long long类型的值。
int *array_local = malloc(64 * sizeof(int));
这句代码声明了一个指向int类型的指针array_local,并使用malloc函数为它分配了足够存储64个int类型数据的内存空间。64 * sizeof(int)是计算64个int类型数据总大小的操作,确保分配的内存可以存放一个包含64个整数的数组。
2.3 替代方案分析
本质上是使用栈内存(stack memory)来替代malloc函数动态分配的堆内存(heap memory)。
- long long _out_accum; 这行代码在栈上声明了一个long long类型的变量_out_accum。这意味着不需要动态分配内存,因为_out_accum的大小在编译时就已经确定了。
- long long *out_accum = &_out_accum; 这行代码创建了一个指向_out_accum的指针out_accum。这样,我们就可以像使用动态分配的内存那样使用_out_accum,但实际上它是在栈上分配的,这使得内存的分配和释放更加高效。
- int _array_local[64]; 这行代码在栈上声明了一个包含64个整数的数组_array_local。与malloc不同,这里不需要在程序运行时分配内存,因为数组的大小在编译时就已经确定了。
- int *array_local = &_array_local[0]; 这行代码创建了一个指向数组第一个元素的指针array_local。这允许我们通过指针来访问和操作数组,就像它是通过malloc动态分配的一样。
3. 总结
Vitis HLS不支持动态创建或删除C/C++对象,因此开发者必须寻找替代方案。本文通过一个例子展示了如何在不定义USE_MALLOC的情况下,使用栈内存代替堆内存进行内存分配。示例中的函数example通过两个循环处理输入数组,使用栈上的局部变量而非malloc分配的内存,从而在编译时确定内存大小,这对硬件合成至关重要。