Инициализируйте огромный массив uint8 t статически с разумным временем компиляции
Я хотел бы статически инициализировать огромный (мегабайт) массив uint8_t.
в начале я попытался это:
constexpr uint8_t arr[HUGE_SIZE] = { 0, 255, ... };
к сожалению, время компиляции выше очень длинное (без оптимизации - около 30 секунд, оптимизация на - выше часа).
я обнаружил, что время компиляции может быть уменьшено до незначительного (как в случаях оптимизации, так и в случаях), если мы используем строку стиля c инициализация:
constexpr uint8_t arr[HUGE_SIZE + 1] = "x00xFFx...";
это хороший подход в C++? Должен ли я использовать некоторый строковый литерал, чтобы сделать типы обеих сторон вышеуказанного назначения равными?
4 ответов
Если массив действительно большой, рассмотрите возможность использования утилиты для генерации объектного файла из массива. Например, с помощью ассемблера GNU вы можете сделать что-то вроде этого:
.section .rodata # or .data, as needed
.globl arr
arr:
.incbin "arr.bin" # assuming arr.bin is a file that contains the data
.size arr,.-arr
затем соберите этот файл с помощью ассемблера GNU и свяжите его с вашей программой. Чтобы использовать эти данные в другом месте вашей программы, просто объявите его как extern "C"
:
extern "C" const uint8_t arr[];
обнаружил, что время компиляции для больших массивов немного улучшается, если массив разбит на более мелкие куски. Тем не менее, струнный подход все еще значительно быстрее. При такой схеме, истинный массив может union
это массив массивов.
публикация ниже в качестве примера того, как проверить проблему OP без явного кодирования миллионов исходных файлов байтов. Поскольку это не так много ответа, но ресурс для исследования, отмечая эту Вики сообщества.
#include <iostream>
using namespace std;
#include <cstdint>
#define METHOD 5
#if METHOD == 1
// 1 byte blocks 28 secs
#define ZZ16 65, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
#define ZZ256 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16
#define ZZ4K ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256
#define ARR constexpr uint8_t arr[]
#define COUT cout << arr << endl
#elif METHOD == 2
// 16 byte blocks 16 secs
#define ZZ16 {66, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255},
#define ZZ256 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16
#define ZZ4K ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256
#define ARR constexpr uint8_t arr[][16]
#define COUT cout << arr[0] << endl
#elif METHOD == 3
// 256 byte blocks 16 secs
#define ZZ16 67, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
#define ZZ256 {ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16},
#define ZZ4K ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256
#define ARR constexpr uint8_t arr[][256]
#define COUT cout << arr[0] << endl
#elif METHOD == 4
// 4K byte blocks 13 secs
#define ZZ16 68, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
#define ZZ256 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16
#define ZZ4K {ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256},
#define ARR constexpr uint8_t arr[][4096]
#define COUT cout << arr[0] << endl
#elif METHOD == 5
// String 4 sec
#define ZZ16 "\x45\xFF\x00\xFF\x00\xFF\x00\xFF\x00\xFF\x00\xFF\x00\xFF\x00\xFF"
#define ZZ256 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16 ZZ16
#define ZZ4K ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256 ZZ256
#define ARR constexpr uint8_t arr[]
#define COUT cout << arr << endl
#endif
#define ZZ64K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K ZZ4K
#define ZZ1M ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K ZZ64K
#define ZZ16M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M ZZ1M
// 3 million bytes
ARR = {
ZZ1M ZZ1M ZZ1M
};
int main() {
cout << "!!!Hello World!!!" << endl;
COUT;
cout << sizeof(arr) << endl;
return 0;
}
вы собираетесь перекомпилировать файл, в котором массив очень часто определяется? Если нет ,вы можете поместить определение массива в отдельный.cpp файл с декларацией в .H-файл. Таким образом, вы столкнетесь с накладными расходами компиляции только при изменении массива.
переместите определение массива в отдельный файл C и скомпилируйте его как таковой. C++ может ссылаться на внешние глобальные данные из объектных модулей с.
Если gcc
занимает слишком много времени, чтобы скомпилировать его, используйте tcc
.