2015-12-28 10 views
7

Ich möchte das riesige (Megabyte) uint8_t Array statisch initialisieren.Initialisiere riesiges uint8_t Array statisch mit vernünftiger Kompilierungszeit

Am Anfang habe ich versucht, dies:

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

Unfortunatelly, von oben Übersetzungszeit sehr lang ist (keine Optimierung - ca. 30 Sekunden, Optimierungen auf - über Stunden).

Ich fand heraus, dass die Kompilierung auf vernachlässigbare reduziert werden kann (sowohl in der Optimierung aus und Fällen), wenn wir CStrings Initialisierung verwenden:

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

Ist der gute Ansatz in C++? Sollte ich ein String-Literal verwenden, um Typen beider Seiten der obigen Zuweisung gleich zu machen?

+0

Benötigen Sie wirklich ein so großes Array? Vielleicht solltest du über den Algorithmus nachdenken. – Downvoter

+0

@mkk Was ist das Array für und benötigen Sie tatsächlich ein Array mit Speicher zur Kompilierzeit gefüllt? – Poriferous

+0

Ich bin überrascht, dass Optimierungen im ersten Fall einen Unterschied machen. Kann jemand das erklären? – Ctx

Antwort

5

Wenn das Array sehr groß ist, sollten Sie ein Dienstprogramm verwenden, um direkt eine Objektdatei aus dem Array zu generieren. Zum Beispiel mit den GNU-Assembler können Sie etwas zu tun:

.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 

Dann diese Datei mit dem Assembler GNU montieren und verbinden Sie es mit Ihrem Programm. Um diese Daten zu verwenden, an anderer Stelle in Ihrem Programm, erklärt es einfach als extern "C":

extern "C" const uint8_t arr[]; 
+0

Das wäre eine Lösung. Wird die Welt von C++ - Programmierern mit diesem Ansatz nicht zufrieden sein? (-; – mkk

+0

@mkk Nun, mit dieser Lösung arbeiten Sie außerhalb der Programmiersprache C++. Dies gilt jedoch auch für jeden anderen Ansatz. In einer portablen Open-Source-Anwendung würde ich darauf achten, eine Lösung hinzuzufügen auch für Windows – fuz

+0

Sie haben Recht, ich frage mich, ob die Einbettung in die cpp-Datei (wie ich es in Frage stellte) einige Garantien gibt, die bei Ihrem Ansatz verloren gehen, zum Beispiel könnte endianness bei der Entwicklung für verschiedene Dinge beschädigt sein Geräte (wir müssen also eine Version von arr.bin für big-endian und little-endian bereitstellen), habe ich recht? – mkk

0

Beabsichtigen Sie die Datei, in der das Array neu zu übersetzen ist sehr oft definiert? Wenn nicht, könnten Sie die Definition des Arrays in eine separate CPP-Datei mit einer Vorwärtsdeklaration in einer H-Datei einfügen. Sie werden also nur dann mit dem Kompilierungsaufwand konfrontiert, wenn sich das Array ändert.

+0

Während des Entwicklungsprozesses kann sich das Array sogar einmal pro Tag ändern, so dass es keine Sache ist, die Stunde zu verlieren oder mehr zu kompilieren. Jedenfalls danke für die Antwort. (-: – mkk

0

Verschieben Sie die Array-Definition in eine separate C-Datei und kompilieren Sie sie als solche. C++ kann auf externe globale Daten von C-Objektmodulen verweisen.

Wenn gcc zu lange dauert, um es zu kompilieren, verwenden Sie tcc.

+0

'constexpr uint8_t arr [HUGE_SIZE] = {0, 255, ...};' kompiliert nicht in C. Wenn Sie einen anderen Code vorschlagen, vielleicht einen Beitrag, um Ihre Antwort zu klären. – chux

+1

constexpr durch const ersetzen . – chqrlie

1

Gefunden, dass die Kompilierzeit für große Arrays ein bisschen verbessert, wenn das Array in kleinere Stücke aufgeteilt wird. Der String-Ansatz ist jedoch immer noch deutlich schneller. Mit solch einem Schema könnte das wahre Array dieses Array von Arrays sein.

Veröffentlichen Sie das unten als ein Beispiel für das Testen von OP-Problem, ohne explizit Millionen-Byte-Quelldateien zu codieren. Da dies keine große Antwort, sondern eine Ressource für die Untersuchung ist, markieren Sie dieses Community-Wiki.

#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; 
}