PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C, VS2010] sizeof() bei struct


Gast
2012-05-23, 13:15:05
Hi,

ich bin auf folgende Kuriosität gestoßen. Ich habe eine struct und ein Array aus Instanzen dieser struct:

typedef struct TableRow_S
{
char Name[8];
short Number;
} TableRow_T;

TableRow_T table [] = { {"Pferd", 35}, {"Kuh", 121}, {"Esel", 42} };

Die struct entspricht einer Tabellenzeile, bestehend aus einem String und einer Zahl, das Array steht für eine Tabelle aus mehreren Zeilen. So weit so gut.

Jetzt habe ich den Code mal mit Visual Studio 2010 durchdebuggt, und habe mit Erstaunen festgestellt, dass, wenn ich mir den Inhalt des Arrays anzeigen lasse, für das zweite und dritte Element Blödsinn angezeigt wird, nur für das erste Element ist die Anzeige korrekt. Ich habe mir dann mal die Adressen der drei Elemente angesehen und dabei festgestellt, dass die um jeweils 6 Bytes auseinanderlagen. Die korrekte Größe der struct liegt aber bei 10 Bytes (8 chars + 1 short zu 2 Bytes), so dass die Array-Elemente um 10 Bytes auseinanderliegen müssten.

Ich habe mir dann mal im Überwachungsfenster sizeof(TableRow_T) anzeigen lassen, das Ergebnis war korrekt 10. Jetzt kommt's: ich habe mir dann noch sizeof(TableRow_S) anzeigen lassen, und da war das Ergebnis 6! Ich frage mich, wie kommt der Debugger bloß auf die 6?

Tiamat
2012-05-23, 19:41:10
Is das ein 32 bit oder 64bit Projekt ?

Gast
2012-05-24, 09:48:55
64 Bit

GloomY
2012-05-25, 00:08:15
Wenn du "Pferd" im Quelltext schreibst, bedeutet das in C Zweierlei:

Ein Array vom typ char mit Größe 5+1=6 (Terminierung) wird vom Compiler angelegt und mit {'P','f','e','r','d','\'0'} initialisiert.
Der Rückgabewert des Ausdrucks "Pferd" ist ein Zeiger, der mit der Addresse des obigen Arrays initialisiert wird (macht der Linker, da das nicht zur Compile-Zeit feststeht)
Daher kannst du auch z.B. schreiben:
char *c = "Pferd";Hier passieren obige Array-Instanziierung und Zuweisung des Rückgabewertes von "Pferd" an die Variable "c". Somit kannst du danach dann über Dereferenzierung von "c" (bzw. "c" + Offset) auf den Inhalt des Arrays zugreifen.

Ein
char c[8]; ist aber nur ein Array. Es hat keinen Rückgabewert (kein RValue) und Zuweisung ist nur elementweise möglich wie z.B.
c[0] = 'P';
c[1] = 'f';
...Initialisieren kannst du das Ganze nur mit der runden Klammerschreibweise mit Kommata getrennt:
char c[8] = {'P', 'f', 'e', 'r', 'd', '\0'};

Daher klappt meines Wissens nach auch die Initialisierung mit "Pferd" nicht, du musst dafür {'P', 'f', 'e', 'r', 'd', '\0'} schreiben.


Dass der Debugger 6 byte ausspuckt für die Größe verstehe ich nicht ganz. Wenn es ein 32-bit Target wäre, würde ich vermuten, dass er vier Byte für den Rückgabewert von "Pferd" (sizeof(char*)) plus 2 Byte für ein Short berechnet.

Bist du sicher, dass du für 64-bit und nicht für 32-bit kompilierst?

edit: Bekommst du keine Warnings? Schau mal ob du in VS mindestens Warning-Level 3 aktiviert hast?!

Expandable
2012-05-27, 19:22:14
Sehr seltsam; bei mir funktioniert der Code unter VS2010 sowohl in 32 als auch in 64 bit im Debug und im Release Mode einwandfrei (sowohl mit dem C++ als auch mit dem reinen C-Compiler (und dann printf natürlich statt cout). Folgender Code liefert folgenden Output:


typedef struct TableRow_S
{
char Name[8];
short Number;
} TableRow_T;

#include <iostream>
int main()
{
TableRow_T table [] = { {"Pferd", 35}, {"Kuh", 121}, {"Esel", 42} };

std::cout << table[0].Name << ", " << table[1].Name << ", " << table[2].Name << std::endl;
std::cout << sizeof(TableRow_T) << "; " << sizeof(table) << "; " << (char*)&table[1] - (char*)&table[0] << std::endl;
}



Pferd, Kuh, Esel
10; 30; 10


sizeof(TableRow_S) ist bei mir auch 10. Kannst du mal dieses Minimalbeispiel testen, ob da das Problem auch auftritt? Hast du vielleicht in einer anderen Compilation Unit TableRow_S/T ebenfalls (aber anders) definiert? Überschreibt dein Programm vielleicht irgendwo Speicher?

Im Übrigen ist
char c[8] = {'P', 'f', 'e', 'r', 'd', '\0'};
und
char c[8] = "Pferd";
äquivalent, GloomY.

GloomY
2012-06-01, 00:03:21
Im Übrigen ist
char c[8] = {'P', 'f', 'e', 'r', 'd', '\0'};
und
char c[8] = "Pferd";
äquivalent, GloomY.Ja, du hast vollkommen Recht. Da hab' ich wohl was Falsches in Erinnerung gehabt.

Gast
2012-06-03, 00:49:40
1.) Je nach Compilereinstellung wird eine Struct immer auf ein Vielfaches von z.B. 4 oder 16 Bytes angelegt. Das ändert sich schon alleine dadurch, dass du von "Release" auf "Debug" umstellst bzw. umgekehrt.

Besonders bitter wird diese Überlegung mit den Bytes bzw. sizeof, wenn du die struct dann in eine Datei schreiben willst und später eventuell mit einer anderen Compilereinstellung lesen willst.

2.) Siehst du nur in Visual Studio den Datensalat oder existiert dieser auch, wenn du die Variablen ausgibst? Wie verhält sich das Ganze denn, wenn du das Array etwas größer oder kleiner machst bzw. statt dem short einen int?