Forum: Compiler & IDEs sizeof auf strukturmember


von Vlad T. (vlad_tepesch)


Lesenswert?

Hi,
Ich habe eingentlich eine total billige Frage, aber ich krieg es grad 
nicht hin:

wie mache ich ein sizeof auf ein Strukturelement, ohne eine Instanz zu 
haben?

Beispiel:

1
typedef struct A
2
{
3
  int b;
4
  int c;
5
}A;
6
7
uint32_t gesamtgroesse = sizeof( A );
8
uint32_t teilgroesseC1  = sizeof( A::c );  // geht nicht
9
uint32_t teilgroesseC2  = sizeof( A.c );   // geht nicht
10
11
A a;
12
uint32_t teilgroesseC3  = sizeof( a.c );   // geht

gibt es keine Möglichkeit diese Größe ohne eine Instanz zu ermitteln?

Gruß,
Vlad

von Grrrr (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> gibt es keine Möglichkeit diese Größe ohne eine Instanz zu ermitteln?

Klar.
1
typedef ... Btyp
2
typedef ... Ctyp
3
typedef struct A
4
{
5
  Btyp b;
6
  Ctyp c;
7
}A;
8
9
...  = sizeof( Btyp )

von Vlad T. (vlad_tepesch)


Lesenswert?

Grrrr schrieb:
> Vlad Tepesch schrieb:
>> gibt es keine Möglichkeit diese Größe ohne eine Instanz zu ermitteln?
>
> Klar.
> ...

Ja gut, das ist auch nur ein Workaround, keine Lösung.
Erfordert zudem eine Anpassung des Headers in dem die Struktur definiert 
ist.

von Grrrr (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> das ist auch nur ein Workaround, keine Lösung.
Wenn Du meinst.

Das ist Definitionssache. Wenn meine "Lösung" die einzig mögliche ist 
trifft, "Workaround" wohl nicht zu.

Vlad Tepesch schrieb:
> Erfordert zudem eine Anpassung des Headers in dem die Struktur definiert
> ist.

Das kann ich ja nicht wissen, das Du die Strukturdefinition nicht ändern 
kannst oder willst. Schreib das das nächstemal bitte vorher.

von Di P. (drpepper) Benutzerseite


Lesenswert?

wenn ich mich recht erinnere gibt sizeof(...) immer nur die größe des 
typs, ganz unabhängig vom wert zurück.

dynamische objekte gibts hier nicht.

von Vlad T. (vlad_tepesch)


Lesenswert?

eventuell wäre folgendes denkbar:
1
uint32_t teilgroesseC  = sizeof( ((A*)0)->c );

sieht zugegebenermaßen nicht sehr schön aus, sollte aber keine 
Laufzeitprobleme geben, da sizeof zur Compiletime aufgelöst wird.

von Vlad T. (vlad_tepesch)


Lesenswert?

Di Pi schrieb:
> wenn ich mich recht erinnere gibt sizeof(...) immer nur die größe des
> typs, ganz unabhängig vom wert zurück.
>
> dynamische objekte gibts hier nicht.

Das ist klar.
Es hat niemand etwas anderes behauptet.

von Grrrr (Gast)


Lesenswert?

1
uint32_t teilgroesseC  = sizeof( ((A*)0)->c );

Hauptsache keine Workarounds. Nee, klar. ;-)
Der nächste Lint-Lauf wird dann auch noch was dazu sagen.

von Karl H. (kbuchegg)


Lesenswert?

Vlad Tepesch schrieb:
> eventuell wäre folgendes denkbar:
>
>
1
> uint32_t teilgroesseC  = sizeof( ((A*)0)->c );
2
>
>
> sieht zugegebenermaßen nicht sehr schön aus,

müsste gehen.

> sollte aber keine
> Laufzeitprobleme geben, da sizeof zur Compiletime aufgelöst wird.

Ist auch vom C-Standard gedeckt (oder wars der C++ Standard?) Irgendwo 
bei den Pointern gibt es einen Passus, dass bei einem sizeof das 
'vermeintliche Dereferenzieren' eines 0 Pointers erlaubt ist und dass 
das kein echtes Dereferenzieren darstellt sondern nur von der 
Schreibweise her so aussieht.

(Müsste C++ sein, da in C der sizeof ja mitlerweile nicht mehr 
notwendigerweise eine Compiletime Angelegenheit ist)

von Grrrr (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Ist auch vom C-Standard gedeckt (oder wars der C++ Standard?) Irgendwo
> bei den Pointern gibt es einen Passus, dass bei einem sizeof das
> 'vermeintliche Dereferenzieren' eines 0 Pointers erlaubt ist und dass
> das kein echtes Dereferenzieren darstellt sondern nur von der
> Schreibweise her so aussieht.

Aha. Wieder was gelernt.

von Karl H. (kbuchegg)


Lesenswert?

Grrrr schrieb:
>
1
uint32_t teilgroesseC  = sizeof( ((A*)0)->c );
2
>
>
> Hauptsache keine Workarounds. Nee, klar. ;-)
> Der nächste Lint-Lauf wird dann auch noch was dazu sagen.

Seine Lösung ist trotzdem besser als deine.

Wenn immer möglich möchte man beim sizeof die Variable angeben und nicht 
den Datentyp.
Sonst hätte er ja auch gleich

uint32_t teilgroesseC2  = sizeof( int );

schreiben können, wohlwissend dass A.c ein int ist. Nur: Ändert A.c 
seinen Datentyp, so passt sich die Pointer Lösung selbst an. In diesem 
Sinne wird daher mehr Arbeit an den Compiler delegiert, was gut ist, 
weil der bei solchen Sachen keinen Fehler macht.

von Grrrr (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Seine Lösung ist trotzdem besser als deine.

Das sehe ich jetzt auch so.

von Vlad T. (vlad_tepesch)


Lesenswert?

Karl heinz Buchegger schrieb:
> (Müsste C++ sein, da in C der sizeof ja mitlerweile nicht mehr
> notwendigerweise eine Compiletime Angelegenheit ist)

Ist das nicht bei c++ so, dass der sizeof Laufzeitanhängig sein kann?
bei c gibts doch kein RTI
Wäre das bei C der Fall, würde ja aber heißen, das das dereferenzieren 
an der Stelle doch falsch wär.

der Visual c++ compiler schluckt die sache mit dem sizeof(A.c) keine 
Ahnung, ob das eine Eigenheit oder C++ Standard ist. Hab grad kein 
visual C projekt und kein gcc c++ projekt zu Hand.

von Grrrr (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> Hab grad kein
> visual C projekt und kein gcc c++ projekt zu Hand.

Ich habs gerade mal durch den avr-gcc gejagt.
Geht ohne Warnings  und i = 2
1
typedef struct A
2
{
3
  int b;
4
  int c;
5
}A;
6
7
short i;
8
9
int main () {
10
  i = sizeof( ((A*)0)->c );
11
}

Nehme also alles zurück und behaupte das Gegenteil.

von henky (Gast)


Lesenswert?

1
uint32_t teilgroesseC  = sizeof( ((A*)0)->c );
Äh, kann mal bitte jemand übersetzen/erklären? Ich kann das leider nicht 
verstehen...

von Grrrr (Gast)


Lesenswert?

Also,
1
uint32_t teilgroesseC  = sizeof( ((A*)0)->c );

ist eine Variablendeklaration mit Initialisierung.

"uint32_t" ist der Typ und "teilgroesseC" der Name der Variablen.

"sizeof( ((A*)0)->c )" ist der Wert der zugewiesen werden soll.

Inhaltlich geht es darum die Grösse eines Mitgliedes der Strukur mit dem 
Typnamen A zu ermitteln, aber ohne das es solch eine Variable 
überhaupt gibt, was heisst sie ist nicht deklariert (oder per malloc 
alloziiert).

"(A*)0"
Daher wird zunächst eine Adresse 0 genommen und mittels "Cast" dem 
Compiler gesagt, er soll annehmen, das eine Variable mit dem Typnamen A 
an dieser Adresse 0 liegt.

Dann wird mittels des "->" (Strukturverweisopator) auf das Mitglied 
namns C verwiesen und mit "sizeof" dessen Grösse ermittelt.

von Grrrr (Gast)


Lesenswert?

"opator" ist auch nett. Meinte natürlich "Operator".

von Karl H. (kbuchegg)


Lesenswert?

Vlad Tepesch schrieb:
> Karl heinz Buchegger schrieb:
>> (Müsste C++ sein, da in C der sizeof ja mitlerweile nicht mehr
>> notwendigerweise eine Compiletime Angelegenheit ist)
>
> Ist das nicht bei c++ so, dass der sizeof Laufzeitanhängig sein kann?
> bei c gibts doch kein RTI

Aber bei C gibt es seit C99 dynamische Arrays

int foo( int i )
{
  char array[i];

  j = sizeof( array );
}

von Sauger (Gast)


Lesenswert?

Mahlzeit,

schau dir mal offsetof(x,y) an.
offsetof(struct,Element "Dahinter") minus offsetof(struct,Element 
"Davor") lassen sich längen berechnen.

MfG

von Thomas P. (tpircher) Benutzerseite


Lesenswert?

Sauger schrieb:
> schau dir mal offsetof(x,y) an.

Lustigerweise ist das Macro offsetof bei GCC genau mit Vlads Methode der 
Dereferenzierung eines gecasteten Null-Pointers definiert.

von Sauger (Gast)


Lesenswert?

In der AVR stddef.h ister als:

/* Offset of member MEMBER in a struct of type TYPE. */
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)

watcom macht es so:
#define offsetof(__typ,__id) ((size_t)((char *)&(((__typ*)0)->__id) - 
(char *)0))

MfG

von Vlad T. (vlad_tepesch)


Lesenswert?

Sauger schrieb:
> offsetof(struct,Element "Dahinter") minus offsetof(struct,Element
> "Davor") lassen sich längen berechnen.

Das ist natürlich auch nicht das Wahre, da der Code dann abhängig davon 
ist, dass die Strukturmember immer hintereinander sind und nicht 
verschoben werden.

von Sauger (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> Das ist natürlich auch nicht das Wahre, da der Code dann abhängig davon
> ist, dass die Strukturmember immer hintereinander sind und nicht
> verschoben werden.

Welcher Entwickler macht denn sowas? Die Konsequenzen beim umstellen 
sollte man schon im Hinterkopf haben :-)

MfG

von henky (Gast)


Lesenswert?

Grrrr schrieb:
> "(A*)0"
> Daher wird zunächst eine Adresse 0 genommen und mittels "Cast" dem
> Compiler gesagt, er soll annehmen, das eine Variable mit dem Typnamen A
> an dieser Adresse 0 liegt.
Danke!

von Simon K. (simon) Benutzerseite


Lesenswert?

Sauger schrieb:
> Vlad Tepesch schrieb:
>> Das ist natürlich auch nicht das Wahre, da der Code dann abhängig davon
>> ist, dass die Strukturmember immer hintereinander sind und nicht
>> verschoben werden.
>
> Welcher Entwickler macht denn sowas? Die Konsequenzen beim umstellen
> sollte man schon im Hinterkopf haben :-)

Ich glaube du hast das Missverstanden. Was ist, wenn man die 
Konsequenzen grad nicht im Kopf hat? Und eben was umstellt und einen Tag 
nach dem Fehler sucht?

von Karl H. (kbuchegg)


Lesenswert?

Sauger schrieb:
> Vlad Tepesch schrieb:
>> Das ist natürlich auch nicht das Wahre, da der Code dann abhängig davon
>> ist, dass die Strukturmember immer hintereinander sind und nicht
>> verschoben werden.
>
> Welcher Entwickler macht denn sowas? Die Konsequenzen beim umstellen
> sollte man schon im Hinterkopf haben :-)

Idealerweise kann man in einer Struktur umstellen wie man lustig ist, 
solange diese Struktur nicht als Bindeglied zu einem anderen Programm 
fungiert, also eine I/O Struktur ist.
Bei letzterem heißt es sowieso besondere Vorsicht walten zu lassen und 
da ist dann auch ein Kommentar angebracht, dass die Struktur genauso 
aussieht wie sie aussieht, weil sich fremde Programme oder Fileaufbauten 
darauf verlassen.

In allen anderen Fällen sollte man sich der Konsequenzen eines 
Strukturumbaus bewusst sein, wie du richtig sagst aber den falschen 
Schluss ziehst, und den Code so aufbauen, dass sich eine Änderung nicht 
auswirkt.

von Vlad T. (vlad_tepesch)


Lesenswert?

Karl heinz Buchegger schrieb:
> Idealerweise kann man in einer Struktur umstellen wie man lustig ist,

das sollte nicht der Ideao

Karl heinz Buchegger schrieb:
> Aber bei C gibt es seit C99 dynamische Arrays

gibt es eigentlich schon (nach 11 Jahren) Compiler, die das können?

von Stefan E. (sternst)


Lesenswert?

Vlad Tepesch schrieb:

> Karl heinz Buchegger schrieb:
>> Aber bei C gibt es seit C99 dynamische Arrays
>
> gibt es eigentlich schon (nach 11 Jahren) Compiler, die das können?

GCC

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.