Frage

las ich, dass die Reihenfolge der Bit-Felder innerhalb einer Struktur-Plattform spezifisch ist. Was ist, wenn ich verschiedene Compiler-spezifischen Verpackungsoptionen zu verwenden, wird diese Garantie Daten in der richtigen Reihenfolge gespeichert, wie sie geschrieben sind? Zum Beispiel:

struct Message
{
  unsigned int version : 3;
  unsigned int type : 1;
  unsigned int id : 5;
  unsigned int data : 6;
} __attribute__ ((__packed__));

Auf einem Intel-Prozessor mit dem GCC Compiler wurden die Felder im Speicher angelegt, wie sie dargestellt sind. Message.version waren die ersten 3 Bits in dem Puffer, und Message.type gefolgt. Wenn ich äquivalente Struktur Verpackungsoptionen für verschiedene Compiler findet, wird dies Cross-Plattform?

War es hilfreich?

Lösung

Nein, es wird nicht vollständig tragbar sein. Verpackungsmöglichkeiten für structs sind Erweiterungen und sind sich nicht vollständig tragbar. Zusätzlich zu, dass C99 §6.7.2.1 Absatz 10 heißt es: „Die Reihenfolge der Zuordnung von Bit-Feldern innerhalb einer Einheit (hohe Ordnung zu niedriger Ordnung oder niedrige Ordnung zu höherer Ordnung) ist die Implementierung definiert.“

Selbst ein einzelne Compiler könnte das Bit-Feld Layout anders auf der endianness der Zielplattform abhängig, zum Beispiel.

Andere Tipps

Bitfelder sind sehr unterschiedlich von Compiler zu Compiler, sorry.

Mit GCC, Big-Endian-Maschinen legen die Bits großen Ende aus ersten und Little-Endian-Maschinen legen zuerst die Bits wenig Ende aus.

K & R sagt: „Benachbarte [bit-] Feldmitglieder Strukturen gepackt sind in der Implementierung abhängig Speichereinheiten in einer Implementierung abhängige Richtung. Wenn ein Feld ein anderes Feld folgendes paßt nicht ... es kann zwischen den Einheiten oder aufgespalten wird Einheit aufgefüllt werden kann. Einen nicht namentlich genannten Bereich der Breite 0 Kräfte diese Polsterung ... "

Deshalb, wenn Sie Maschine unabhängiges binäres Layout benötigen, müssen Sie es selbst tun.

Diese letzte Aussage gilt auch für Nicht-bitfields aufgrund Polsterung - aber alle Compiler scheinen einen Weg zu haben Byteverpackung einer Struktur zu zwingen, wie ich sehe Sie schon für GCC entdeckt

.

Bitfelder sollte vermieden werden - sie sind nicht sehr portabel zwischen Compiler sogar für die gleiche Plattform. aus dem C99-Standard 6.7.2.1/10 - "Struktur und Vereinigung Bezeich" (gibt es in der C90-Standard eine ähnliche Formulierung):

  

Eine Implementierung zuweisen kann jede adressierbare Speichereinheit groß genug, um einen bitfield zu halten. Wenn genügend Raum verbleibt, ein Bit-Feld, das sofort eine anderes Bit-Feld in einer Struktur folgt, wird in benachbarte Bits der gleichen Einheit verpackt werden. Wenn nicht genügend Raum bleibt, ob ein Bit-Feld, das nicht ist, paßt die nächste Einheit in setzen oder Überlappungen benachbarte Einheiten ist die Implementierung definiert. Die Reihenfolge der Zuteilung von Bit-Feldern innerhalb einer Einheit (hohe Ordnung zu niedriger Ordnung oder niedrige Ordnung zu höherer Ordnung) ist die Implementierung definiert. Die Ausrichtung der adressierbare Speichereinheit ist nicht näher bezeichnet.

Sie können nicht garantieren, ob ein Bit-Feld wird ‚Spanne‘ int Grenze oder nicht und Sie können nicht angeben, ob ein Bitfeld im Low-End des int beginnt oder dem oberen Ende des int (dies ist unabhängig davon, ob der Prozessor ist big-endian oder little-endian).

Bevorzugen Bitmasken. Verwenden Sie inlines (oder auch Makros) zu setzen, löschen und testen Sie die Bits.

endianness sprechen über Bytereihenfolgen nicht wenig Aufträge. Heute , es ist zu 99% sicher, dass Bit-Befehle festgelegt sind. Wenn jedoch bitfields Verwendung endianness sollte in count genommen werden. Siehe das Beispiel unten.

#include <stdio.h>

typedef struct tagT{

    int a:4;
    int b:4;
    int c:8;
    int d:16;
}T;


int main()
{
    char data[]={0x12,0x34,0x56,0x78};
    T *t = (T*)data;
    printf("a =0x%x\n" ,t->a);
    printf("b =0x%x\n" ,t->b);
    printf("c =0x%x\n" ,t->c);
    printf("d =0x%x\n" ,t->d);

    return 0;
}

//- big endian :  mips24k-linux-gcc (GCC) 4.2.3 - big endian
a =0x1
b =0x2
c =0x34
d =0x5678
 1   2   3   4   5   6   7   8
\_/ \_/ \_____/ \_____________/
 a   b     c           d

// - little endian : gcc (Ubuntu 4.3.2-1ubuntu11) 4.3.2
a =0x2
b =0x1
c =0x34
d =0x7856
 7   8   5   6   3   4   1   2
\_____________/ \_____/ \_/ \_/
       d           c     b   a

Die meisten der Zeit, wahrscheinlich, aber nicht den Hof darauf wetten, denn wenn Sie falsch sind, werden Sie große verlieren.

Wenn Sie wirklich, wirklich identische binäre Informationen haben müssen, müssen Sie bitfields mit Bitmasken schaffen - zum Beispiel Sie verwenden ein unsigned short (16 Bits) für Nachricht, und dann Dinge wie versionMask = 0xE000 die drei obersten Bits darzustellen.

Es gibt ein ähnliches Problem mit Ausrichtung innerhalb structs. Zum Beispiel Sparc, PowerPC und 680x0 CPUs sind all Big-Endian-und der gemeinsame Standard für Sparc und PowerPC-Compiler ist struct Mitglieder auf 4-Byte-Grenzen ausgerichtet ist. ein Compiler, den ich für 680x0 verwenden nur auf 2-Byte-Grenzen ausgerichtet ist jedoch - und es gab keine Möglichkeit, die Ausrichtung zu ändern

So für einige structs, die Größen auf Sparc und PowerPC sind identisch, aber kleiner auf 680x0, und einige der Mitglieder sind in verschiedenen Speicherverschiebungen innerhalb der Struktur.

Das war ein Problem mit einem Projekt arbeitete ich an, weil ein Server-Prozess auf Sparc läuft eine Client-Abfrage würde und herausfinden, es Big-Endian war, und annimmt, dass es nur binären structs auf dem Netzwerk heraus spritzen konnte und der Kunde konnte bewältigen. Und das war für PowerPC-Kunden gut, und abgestürzt große Zeit auf 680x0 Kunden. Ich habe den Code nicht schreiben, und es dauerte eine ganze Weile, um das Problem zu finden. Aber es war einfach zu beheben, sobald ich.

Natürlich ist die beste Antwort ist, eine Klasse zu verwenden, die liest / schreibt Bitfelder als Stream. Unter Verwendung der Bit-Feldstruktur C ist gerade nicht garantiert. Nicht zu erwähnen, es unprofessionell / faul / dumm gilt als dies in der realen Welt verwenden Codierung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top