2016-04-06 16 views
2

zu mehrdimensionalen Array von einem anderen Typ I habenmehrdimensionales Array Guss

const uint8_t longByteTable[16][256][16] = { { { 0x00, ... } } }; 

als dreidimensionale 16x256x16 Array von fest codierten Werte Oktett erklärt.

I
const uint64_t reinterpretedTable[16][256][2]; 

Was eine gültige WeiselongByteTablezu werfen brauchen, ist:

Zur Optimierung und verschiedene andere Gründe, warum ich dieses Array benötigen als dreidimensionale 16x256x2 Array von uint64_t Werte interpretiert werdenreinterpretedTableinnerhalb der strikten ISO/ANSI C. Ist das:

const uint64_t (*reinterpretedTable)[256][2] = 
    (const uint64_t(*)[256][2])longByteTable; 

ein richtiger Weg, das zu tun?

P.S. Ich kann longByteTable mit letztem Typ nicht erklären, weil es dann nicht richtig mit unterschiedlichem endianess funktionieren würde, und ich entweder verschiedene Tabellen für diffendiannes endianness erklären oder einige Laufzeitkontrollen und Umdrehungen durchführen müsste. Und ja, alle weiteren Transformationen des neuinterpretierten Arrays sind endianitätsinvariant.

+1

"Ich kann' longByteTable' nicht mit letzterem Typ deklarieren, weil es dann nicht mit unterschiedlicher Endianz funktionieren würde. "Das klingt sehr nach einem X/Y-Problem. Wenn Sie "neuinterpretierteTabelle" erstellen müssen, um einen bestimmten Umgang mit der Endianz zu gewährleisten, sollten Sie in der Lage sein, es portabler zu machen - zum Beispiel mit 'hton' /' ntoh' Funktionen. – dasblinkenlight

+0

Nein, ich brauche die Konvertierungen und das Byte nicht. Alle Transformationen sind endianitätsunabhängig, wie Xor's und Zuweisungen. Aber xoring-Werte vom Typ 'uint64_t' sind in meinem Fall viel schneller als das xoring von 4 Wertepaaren vom Typ 'uint8_t', weil es mit einer einzelnen Anweisung anstelle von 4 separaten Anweisungen ausgeführt wird. Ja, manchmal sieht der Compiler dies durch und ersetzt Bytes xor durch Vollregister-XORs, aber nicht die ganze Zeit. – aprelev

Antwort

2

Aufgrund der Zeiger-Aliasing-Regeln von C können Sie solche Umwandlungen nicht durchführen. Der einzig sichere Weg, um eine Vereinigung zu nutzen:

typedef union 
{ 
    uint8_t longByteTable[16][256][16] 
    uint64_t reinterpretedTable[16][256][2]; 
} table_t; 

const table_t table; 

Obwohl beachten Sie, dass dies immer noch den Code machen wird davon abhängen, Endianess. Die einzige Möglichkeit, den Code endianessunabhängig zu machen, besteht darin, Werte mit Hilfe von Bitverschiebungen größeren Integer-Typen zuzuweisen.

+0

Danke, das funktioniert tatsächlich. Schade, ich habe vorher noch nicht an Gewerkschaften gedacht. – aprelev

+0

Schließlich gelöst mit Vereinigung von Zeigern: 'union longTable_t { const uint8_t (* asBytes) [256] [16]; const uint64_t (* asQWords) [256] [2]; }; ' – aprelev

+0

@ArsenyAprelev Nein, Sie sollten eine Struktur wie oben haben dann einen Zeiger auf diese Struktur deklarieren. Das Problem mit Zeiger-Aliasing besteht darin, dass ein Compiler davon ausgehen kann, dass auf einen bestimmten Datenblock nur über einen Zeiger auf diesen bestimmten Typ zugegriffen werden kann. Wenn auf einen anderen Typ verwiesen wird, darf der Compiler weiterhin annehmen, dass keine Änderungen an den Daten vorgenommen wurden, und daher den Code entsprechend optimieren. Eine Vereinigung von Zeigern löst also nichts. [Siehe hierzu] (http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) für Details. – Lundin