如何在不浪费 C 语言内存的情况下创建快速且巨大的联合数组?

How to create a fast & huge union array without wasting memory in C?

我想使用 union 在同一内存中存储不同的数据类型。该数组长度固定,访问速度快,内存浪费尽可能小。

我将定义存储相同数据类型的区域。所以我这样做:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <inttypes.h>

#define RESERVED_BYTES 1073741824
//#define RESERVED_BYTES 2147483648

typedef union {
    char c[RESERVED_BYTES];             //1Byte
    uint8_t u8[RESERVED_BYTES];         //1Byte
    uint16_t u16[RESERVED_BYTES / 2];   //2Byte
} array_type;

int main(void)
{
    array_type *array;
    array = calloc(1, sizeof(array_type));

    getchar();
    return 0;
}

这段代码有效并分配了 1GB 的内存,并且该数组的元素可以与 array[0].u8[3] 一起使用,例如我知道我必须处理索引,因为它们取决于字节大小。

遗憾的是,如果我增加内存大小(请参阅 #define RESERVED_BYTES 2147483648)并且在 64 位计算机上使用 MSVS 2013,我会收到 error C2148: total size of array must not exceed 0x7fffffff bytes 代码无法编译。另一方面,像 array = calloc(2147483648, sizeof(*array));.

这样直接将 2GB 放入 calloc 是没有问题的

但是这个版本我可能会浪费内存:

union {
    char c;             //1Byte
    uint8_t u8;         //1Byte
    uint16_t u16;   //2Byte
} *array;

或者需要构建一个耗时的函数来计算我想避免的两个索引:

union {
    char c[2];             //1Byte
    uint8_t u8[2];          //1Byte
    uint16_t u16[1];    //2Byte
} *array;
array[3].u8[2] = 1;

那么如何处理这个问题呢?

I'd like to store different datatypes in the same memory using union. This array has a fixed length

根据您发布的代码,数组具有相同的 字节 长度,但根据它们的不同 不同 个元素类型。

I receive an error C2148: total size of array must not exceed 0x7fffffff bytes.

如果我猜的话,这可能与甚至适用于 64 位编译的 static 数据的 2 GB 限制有关,这意味着 array_type 永远无法实例化为 global/static 变量或 local/stack 变量 (Memory Limits for Applications on Windows)。最后,这意味着剩下的唯一选择就是在堆上动态分配这样一个数组。

But with this version I might waste memory
...or need to build a time-consuming function that calculates the both indices

您可以通过稍微修改 union 定义来实现(几乎)相同的效果,而不会浪费内存,也不需要额外的访问器。

#define RESERVED_BYTES 2147483648

typedef union {
    void *pv;
    char *pc;
    uint8_t *pu8;
    uint16_t *pu16;
} parray_type;

int main(void)
{
    parray_type parray;
    parray.pv = calloc(RESERVED_BYTES, 1);

    // last element in allocated buffer for each type
    char c = parray.pc[RESERVED_BYTES - 1];
    uint8_t u8 = parray.pu8[RESERVED_BYTES - 1];
    uint16_t u16 = parray.pu16[RESERVED_BYTES / 2 - 1];

    return 0;
}

当然,您必须始终记住 pu16 的最大索引是 pcpu8 的一半,但这也是原始代码中的前提.