如何创建快速&巨大的联合数组没有在C中浪费内存?

时间:2016-01-06 01:05:27

标签: c arrays memory unions

我想使用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。另一方面,将{2}直接放入与calloc类似的array = calloc(2147483648, sizeof(*array));中是没有问题的。

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

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;

那么如何处理这个问题?

1 个答案:

答案 0 :(得分:4)

  

我想使用union将不同的数据类型存储在同一个内存中。该数组具有固定长度

根据您发布的代码,数组具有相同的字节 -length,但根据其类型保存不同的数量的元素。

  

我收到错误C2148:数组的总大小不得超过0x7fffffff字节。

如果我猜测,这可能与静态数据的2 GB限制有关,甚至适用于64位编译,这意味着array_type类型的联合永远不会被实例化为全局/静态变量或本地/堆栈变量(Memory Limits for Applications on Windows)。最后,这意味着剩下的唯一选择是在堆上动态分配这样的数组。

  

但是使用这个版本我可能会浪费内存   
......或者需要建立一个耗时的函数来计算两个指数

您可以通过稍微修改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的一半,但这也是原始代码中的前提。< / p>