Was ist falsch an dieser C-Funktion, um die Endianess einer Maschine zur Laufzeit zu finden?

8

Das habe ich heute bei einem Interview angeboten.

%Vor%

Mein Interviewer bestand darauf, dass c und l nicht garantiert an der gleichen Adresse beginnen. Daher sollte die Union geändert werden, um char c[sizeof(long)] zu sagen und der Rückgabewert sollte in u.c[0] == 1 geändert werden.

Stimmt es, dass Mitglieder einer Gewerkschaft möglicherweise nicht an derselben Adresse beginnen?

    
sigjuice 20.08.2009, 02:45
quelle

8 Antworten

6

Sie haben Recht damit, dass die "Mitglieder einer Gewerkschaft vielleicht an derselben Adresse beginnen". Der maßgebliche Teil des Standards ist (6.7.2.1 Abs. 13) :

  

Die Größe einer Union reicht aus, um die größten ihrer Mitglieder zu enthalten. Der Wert von höchstens einem der Mitglieder kann jederzeit in einem Union-Objekt gespeichert werden. Ein Zeiger auf ein Union-Objekt, das entsprechend konvertiert wird, zeigt auf jedes seiner Elemente (oder wenn ein Element ein Bit-Feld ist, dann auf die Einheit, in der es sich befindet) und umgekehrt.

Grundsätzlich ist eine Startadresse der Union garantiert die gleiche wie die Startadresse jedes seiner Mitglieder. Ich glaube (auf der Suche nach der Referenz), dass ein long garantiert größer ist als ein char . Wenn Sie dies annehmen, sollte Ihre Lösung gültig sein .

* Ich bin immer noch ein wenig unsicher, da es einige interessante Formulierungen rund um die Darstellung ganzzahliger und insbesondere vorzeichenbehafteter Integer-Typen gibt. Lesen Sie die Abschnitte 6.2.6.2 und 1 & amp; 2.

    
D.Shawley 20.08.2009, 03:41
quelle
8

Ich war unsicher über die Mitglieder der Gewerkschaft, aber SO kam zu Hilfe .

Die Prüfung kann besser geschrieben werden als:

%Vor%

Übrigens zeigt die C-FAQ beide Methoden: Wie kann ich feststellen, ob die Bytereihenfolge einer Maschine big-endian oder wenig ist? Endian?

    
Sinan Ünür 20.08.2009 02:52
quelle
3

Während Ihr Code wahrscheinlich in vielen Compilern funktioniert, hat der Interviewer Recht - wie man Felder in einer Union oder einer Struktur ausrichtet, liegt ganz bei dem Compiler und in diesem Fall könnte der Char entweder am "Anfang" oder am Ende platziert werden "Ende". Der Code des Interviewers lässt keinen Zweifel aufkommen und funktioniert garantiert.

    
Kristoffon 20.08.2009 02:54
quelle
1

Der Standard sagt, dass die Offsets für jedes Element in einer Union Implementierung definiert sind.

  

Wenn ein Wert in einem Member eines Objekts vom Union-Typ gespeichert wird, werden die Bytes des Objekts angezeigt   Darstellung, die nicht diesem Mitglied entspricht, aber anderen Mitgliedern entspricht   nimm unspezifizierte Werte.    ISO / IEC 9899: 1999 Darstellung der Typen 6.5.6.2, Abs. 7 (pdf-Datei )

Daher ist es Sache des Compilers, zu wählen, wo das Zeichen innerhalb der Union relativ zum Long platziert werden soll - sie haben nicht garantiert dieselbe Adresse.

    
fbrereto 20.08.2009 02:52
quelle
0

Ich habe eine Frage dazu ...

Wie ist

?

u.c [0] == alles

gültig gegeben:

%Vor%

Wie funktioniert [0] auf einem Zeichen?

Scheint mir, es wäre äquivalent zu: (* u.c + 0) == irgendwas, was, naja, Mist wäre, wenn man den Wert von u.c betrachtet, der wie ein Zeiger behandelt wird, wäre Mist.

(Außer vielleicht, wie es mir jetzt einfällt, aß irgendein HTML-Mist-Code ein kaufmännisches Und-Zeichen in der ursprünglichen Frage ...)

    
smcameron 20.08.2009 03:06
quelle
0

Obwohl der Interviewer korrekt ist und dies nicht garantiert ist, funktioniert auch keine der anderen Antworten, da ein Dereferenzieren eines Zeigers nach dem Umwandeln in einen anderen Typ zu undefiniertem Verhalten führt.

In der Praxis wird dies (und die anderen Antworten) immer funktionieren, da alle Compiler transparent zwischen Pointer-zu-Union- und Pointer-zu-Union-Elementen umwandeln können - viel alter Code wird nicht funktionieren, wenn sie funktionieren nicht.

    
Chris Dodd 20.08.2009 03:09
quelle
0

korrigiere mich, wenn ich falsch liege, aber lokale Variablen nicht auf 0 initialisiert werden;

das ist nicht besser:

%Vor%     
Mandrake 21.10.2009 16:45
quelle
0

Ein noch nicht erwähnter Punkt ist, dass der Standard explizit die Möglichkeit zulässt, dass Integer-Repräsentationen Padding-Bits enthalten können. Persönlich wünschte ich, das Standardkomitee würde einem Programm eine einfache Möglichkeit geben, bestimmte erwartete Verhaltensweisen zu spezifizieren, und verlangen, dass jeder Compiler diese Spezifikationen entweder respektieren oder die Kompilierung ablehnen muss; Code, der mit einer "Integers darf keine Padding-Bits" -Spezifikation hat, wäre dann berechtigt, davon auszugehen, dass dies der Fall ist.

Wie dem auch sei, wäre es vollkommen legitim (wenn auch ungerade), dass eine Implementierung 35-Bit long -Werte als vier 9-Bit-Zeichen im Big-Endian-Format speichert, aber das LSB des ersten Bytes als a Paritätsbit. Bei einer solchen Implementierung könnte das Speichern von 1 in long dazu führen, dass die Parität des gesamten Worts ungerade wird, was die Implementierung zwingt, 1 in das Paritätsbit zu speichern.

Ein solches Verhalten wäre zwar seltsam, aber wenn Architekturen, die Padding verwenden, ausreichend auffällig sind, um explizite Bestimmungen im Standard zu rechtfertigen, kann Code, der auf solchen Architekturen bricht, nicht wirklich als "portabel" angesehen werden. p>

Der Code, der union verwendet, sollte auf allen Architekturen korrekt funktionieren, die einfach als "big-endian" oder "little-endian" bezeichnet werden können und keine Füllbits verwenden. Es wäre auf einigen anderen Architekturen bedeutungslos (und in der Tat könnten die Begriffe "big-endian" und "little-endian" ebenfalls bedeutungslos sein).

    
supercat 10.03.2015 17:27
quelle

Tags und Links