2010-11-29 4 views
11

Wie kann ich Strukturauffüllung in C deaktivieren, ohne Pragma zu verwenden?Strukturauffüllung in C deaktivieren, ohne Pragma zu verwenden

+0

Dies ist nicht Standard. Ob (und wenn ja wie) dies möglich ist, hängt ganz davon ab, welche Implementierung von C Sie verwenden. –

+0

Ich denke, es gibt keinen anderen Weg, dies zu tun. – frast

+0

Warum können Sie Pragma nicht verwenden? –

Antwort

16

4 Byte-Grenzen haben Es gibt keinen Standard Art und Weise dies zu tun. Der Standard besagt, dass das Auffüllen nach Ermessen der Implementierung erfolgen kann. Von C99 6.7.2.1 Structure and union specifiers Absatz 12:

Jedes nicht-Bitfeld Element einer Struktur oder Vereinigung Aufgabe wird bei einer Implementierung definierte angemessene Weise auf seinen Typen ausgerichtet ist.

Nachdem das gesagt wurde, gibt es ein paar Dinge, die Sie ausprobieren können.


Die erste haben Sie bereits diskontiert, #pragma mit dem Compiler zu versuchen und zu überzeugen, nicht zu packen. In jedem Fall ist dies nicht tragbar. Es gibt auch keine anderen implementierungsspezifischen Möglichkeiten, aber Sie sollten diese überprüfen, wenn Sie diese Fähigkeit wirklich benötigen.


Die zweite ist Ihre Felder in der größten zur kleinsten Auftrag wie alle long long Typen von den long diejenigen gefolgt, um zu bestellen, dann die alle int, short und schließlich char Typen. Dies wird normalerweise funktionieren, da es meistens die größeren Typen sind, die die strengeren Ausrichtungsanforderungen haben. Wiederum nicht tragbar.


Drittens können Sie Ihre Typen als char Arrays definieren und die Adressen werfen, um sicherzustellen, gibt es keine Polsterung. Bedenken Sie jedoch, dass einige Architekturen langsamer werden, wenn die Variablen nicht korrekt ausgerichtet sind und andere wiederum kläglich ausfallen (z. B. einen BUS-Fehler auslösen und Ihren Prozess beenden).

Dieser letzte trägt eine weitere Erklärung. Angenommen, Sie haben eine Struktur mit den Feldern in der folgenden Reihenfolge:

char C; // one byte 
int I; // two bytes 
long L; // four bytes 

Mit Polsterung, Sie mit dem folgende Bytes können am Ende:

CxxxIIxxLLLL 

wo x die Polsterung ist.

Wenn Sie jedoch Ihre Struktur definieren als:

typedef struct { char c[7]; } myType; 
myType n; 

Sie erhalten:

CCCCCCC 

Sie können dann so etwas wie:

int *pInt = &(n.c[1]); 
int *pLng = &(n.c[3]); 
int myInt = *pInt; 
int myLong = *pLng; 

Sie geben:

CIILLLL 

Wiederum leider nicht tragbar.


All diese "Lösungen" basieren auf vertrauten Kenntnissen Ihres Compilers und der zugrunde liegenden Datentypen.

+1

Beachten Sie, dass bei einigen Systemen der Zugriff auf falsch ausgerichtete Adressen ('int * pLng = & (n.c [3]); int myLong = * pLng;') fehlschlägt (z. B. 68000 und ARM schlägt fehl). Daher ist dort Auffüllen erforderlich. – Vovanium

+0

Einverstanden, @Vovanium, daher mein "schief kläglicher" Kommentar. – paxdiablo

3

Außer Compiler-Optionen wie Pragma-Pack können Sie nicht, Padding ist in der C-Standard.

Sie können immer versuchen, Polsterung zu reduzieren, indem die kleinsten Arten zuletzt in der Struktur, wie in deklarieren:

struct _foo { 
    int a; /* No padding between a & b */ 
    short b; 
} foo; 

struct _bar { 
    short b; /* 2 bytes of padding between a & b */ 
    int a; 
} bar; 

Hinweis für Implementierungen, die

1

Bei einigen Architekturen wird die CPU selbst ablehnen, wenn sie aufgefordert wird, an fehlausgerichteten Daten zu arbeiten. Um dies zu umgehen, könnte der Compiler mehrere ausgerichtete Lese- oder Schreibbefehle erzeugen, die verschiedenen Bits verschieben und teilen oder zusammenführen. Sie können vernünftigerweise erwarten, dass es 5- oder 10-mal langsamer ist als die ausgerichtete Datenverarbeitung. Aber der Standard erfordert keine Compiler, um darauf vorbereitet zu sein ... angesichts der Leistungskosten ist es einfach nicht genug nachgefragt. Die Compiler, die die explizite Kontrolle über das Padding unterstützen, stellen ihre eigenen Pragmas zur Verfügung, gerade weil die Pragmas für Nicht-Standard-Funktionalität reserviert sind.

Wenn Sie mit nicht gepolsterten Daten arbeiten müssen, sollten Sie Ihre eigenen Zugriffsroutinen schreiben. Möglicherweise möchten Sie mit Typen experimentieren, die weniger Ausrichtung erfordern (z. B. char/int8_t verwenden), aber es ist immer noch möglich, dass z. Die Größe von Strukturen wird auf ein Vielfaches von 4 aufgerundet, was die Packstrukturen straff macht. In diesem Fall müssen Sie Ihren eigenen Zugriff für die gesamte Speicherregion implementieren.

0

Entweder lassen Sie Compiler tun Padding, oder sagen Sie es nicht mit #pragma zu tun, entweder Sie nur einige Bündel von Bytes wie ein Char-Array verwenden, und Sie bauen alle Ihre Daten selbst (Verschieben und Hinzufügen von Bytes). Das ist wirklich ineffizient, aber Sie werden das Layout der Bytes genau steuern. Ich habe manchmal Netzwerkpakete manuell vorbereitet, aber in den meisten Fällen ist es eine schlechte Idee, auch wenn es Standard ist.

0

Wenn Sie wirklich Strukturen ohne Auffüllung wollen: Definieren Sie Ersatzdatentypen für kurz, int, long, etc., mit Strukturen oder Klassen, die nur aus 8-Bit-Bytes bestehen. Stellen Sie dann Ihre Strukturen auf höherer Ebene mit den Ersatzdatentypen zusammen.

C++ ist das Überladen von Operatoren sehr praktisch, aber Sie könnten den gleichen Effekt in C mit Strukturen anstelle von Klassen erreichen. Die unten angegebenen Implementierungs- und Zuweisungsimplementierungen gehen davon aus, dass die CPU fehlausgerichtete 32-Bit-Ganzzahlen verarbeiten kann, aber andere Implementierungen könnten strengere CPUs aufnehmen. Hier

ist Beispielcode:

#include <stdint.h> 
#include <stdio.h> 

class packable_int { public: 

    int8_t b[4]; 

    operator int32_t() const  { return *(int32_t*) b; } 
    void operator = (int32_t n) { *(int32_t*) b = n; } 

}; 

struct SA { 
    int8_t c; 
    int32_t n; 
} sa; 

struct SB { 
    int8_t  c; 
    packable_int n; 
} sb; 

int main() { 
    printf ("sizeof sa %d\n", sizeof sa); // sizeof sa 8    
    printf ("sizeof sb %d\n", sizeof sb); // sizeof sb 5    
    return 0; 
} 
0

Wir Struktur padding in C-Programm deaktivieren können eine beliebige der folgenden Verfahren.

-> verwenden __attribute__((packed)) hinter der Definition der Struktur. für z.

struct node { 
    char x; 
    short y; 
    int z; 
} __attribute__((packed)); 

->-fpack-struct Flag verwenden, während C-Code zu kompilieren. für z.

$ gcc -fpack-struct -o tmp tmp.c

Hoffnung, das hilft. Danke.