Статическая инициализация огромного массива uint8_t с разумным временем компиляции

Я хотел бы статически инициализировать огромный (мегабайт) массив uint8_t.

В начале я попробовал это:

constexpr uint8_t arr[HUGE_SIZE] = { 0, 255, ... };

К сожалению, время компиляции выше очень велико (без оптимизации — около 30 секунд, оптимизация — выше часа).

Я обнаружил, что время компиляции может быть уменьшено до незначительного (как при выключенной, так и при оптимизации), если мы используем инициализацию строки стиля c

constexpr uint8_t arr[HUGE_SIZE + 1] = "\x00\xFF\x...";

Это хороший подход в C ++? Должен ли я использовать какой-либо строковый литерал, чтобы сделать типы обеих сторон вышеуказанного присваивания равными?

7

Решение

Если массив действительно большой, рассмотрите возможность использования утилиты для непосредственного создания объектного файла из массива. Например, с помощью ассемблера 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[];
5

Другие решения

Обнаружено, что время компиляции для больших массивов действительно немного улучшается, если массив разбивается на более мелкие куски. Тем не менее строковый подход все еще значительно быстрее. При такой схеме истинный массив мог 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;
}
1

Вы собираетесь перекомпилировать файл, в котором массив определяется очень часто? Если нет, вы можете поместить определение массива в отдельный файл .cpp с предварительным объявлением в файле .h. Таким образом, вы столкнетесь с издержками компиляции только при изменении массива.

0

Переместите определение массива в отдельный файл C и скомпилируйте его как таковой. C ++ может ссылаться на внешние глобальные данные из объектных модулей C.

Если gcc занимает слишком много времени, чтобы скомпилировать его, используйте tcc ,

0
По вопросам рекламы [email protected]