Ist es in Ordnung, verschiedene Datentypen in demselben zugewiesenen Speicher in C zu speichern?

8

Ich möchte verschiedene Datentypen in demselben zugewiesenen Speicher speichern, um die Ausführungszeit zu reduzieren, indem ich den Speicher nur einmal zuweise. Ich fand heraus, dass es tatsächlich möglich ist, ein Array von uint8_t Variablen zu erstellen und einen neuen uint16_t Zeiger auf die gleiche Speicheradresse zu erstellen, und dann kann ich beide Werte lesen.

Das erlaubt mir, einen Zeiger zu erstellen, sagen wir in die Mitte des zugewiesenen Speichers und speichert die Werte in der zweiten Hälfte in einem anderen Datentyp.

Ist das in Ordnung? Ich weiß, dass ich auf die Speichergrenzen achten muss, aber ist das ein schlechter Stil?

Hier mein Code:

%Vor%     
TimFinnegan 31.12.2015, 17:03
quelle

2 Antworten

10

Verwenden Sie union , um eine Variable zu erstellen, die manchmal einen Typ speichert, manchmal einen anderen.

%Vor%

Dies verwendet nicht den gesamten Speicherplatz mit nur einem uint8_t u8 pro Union. Das Folgende verwendet 2 uint8_t .

%Vor%

OTOH Wenn Code ein ganzes Array fester Länge überlagern muss

%Vor%     
chux 31.12.2015, 17:38
quelle
4
  

Ist das in Ordnung?

Der Standard sagt:

  

Ein Zeiger auf einen Objekttyp kann in einen Zeiger auf einen anderen Objekttyp umgewandelt werden. Wenn der resultierende Zeiger für den referenzierten Typ nicht korrekt ausgerichtet ist, ist das Verhalten nicht definiert. Andernfalls wird das Ergebnis bei der erneuten Konvertierung mit dem ursprünglichen Zeiger verglichen.

(C2011, 6.3.2.3/7)

Beachten Sie, dass Sie den konvertierten Zeiger nicht einmal verwenden müssen, um undefiniertes Verhalten zu erzeugen - das Verhalten der Konvertierung selbst ist nicht definiert.

Damit hat Ihr Beispielcode einen Sonderfall: Der Zeiger, der von einem erfolgreichen Aufruf von calloc() (oder malloc() oder realloc() ) zurückgegeben wird, wird garantiert passend für ein Objekt eines beliebigen Typs ausgerichtet Die spezifische Zeigerkonvertierung, die Sie durchführen ( array2 = &array[0] ) sollte immer in Ordnung sein. Es sollte jedoch eine Besetzung erforderlich sein. Dein Compiler sollte dich davor warnen.

Wenn Sie stattdessen Zeiger auf beliebige Positionen im Inneren des zugewiesenen Blocks konvertieren möchten, können Sie sich nicht darauf verlassen, dass die Ausrichtung korrekt ist.

Beachten Sie auch, dass Sie bei diesem Schema die Leistung beeinträchtigen, anstatt sie zu verbessern. Insbesondere haben einige Prozessoren eine viel bessere Lade- und Speicherleistung für Daten, die entsprechend ausgerichtet sind, obwohl sie eine andere Ausrichtung verarbeiten können. Sie zahlen die Kosten für die Speicherzuweisung einmal pro Block. Sie bezahlen jeden falsch ausgerichteten Zugriff für jeden Zugriff.

  

Ich weiß, dass ich auf die Speichergrenzen achten muss, aber ist das ein schlechter Stil?

Ja, sehr. Sie opfern Code-Klarheit für einen unsicheren, hypothetischen Leistungsgewinn. Die erhöhten Entwicklungs- und Wartungskosten werden wahrscheinlich jeden Leistungsgewinn überfluten, insbesondere da Sie Ihre Absicht für den Compiler ebenfalls verschleiern und es dadurch schwieriger machen, effizienten Maschinencode zu generieren.

Außerdem ist es wahrscheinlich viel zu früh, um mit dieser Art von Mikrooptimierung zu beginnen. Machen Sie Ihr Programm zuerst korrekt. Wenn es nicht schnell genug ist, testen , um die Engpässe zu finden und sich auf die Verbesserung dieser Teile zu konzentrieren. Sie werden wahrscheinlich die Leistung verbessern, indem Sie bessere Algorithmen wählen. kleine Tricks, wie Sie es vorschlagen, sind es selten wert.

    
John Bollinger 31.12.2015 17:52
quelle

Tags und Links