mikrocontroller.net

Forum: Compiler & IDEs sizeof auf strukturmember


Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht 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:


typedef struct A
{
  int b;
  int c;
}A;

uint32_t gesamtgroesse = sizeof( A );
uint32_t teilgroesseC1  = sizeof( A::c );  // geht nicht
uint32_t teilgroesseC2  = sizeof( A.c );   // geht nicht

A a;
uint32_t teilgroesseC3  = sizeof( a.c );   // geht

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

Gruß,
Vlad

Autor: Grrrr (Gast)
Datum:

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

Klar.
typedef ... Btyp
typedef ... Ctyp
typedef struct A
{
  Btyp b;
  Ctyp c;
}A;

...  = sizeof( Btyp )


Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Di Pi (drpepper) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
eventuell wäre folgendes denkbar:
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.

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
uint32_t teilgroesseC  = sizeof( ((A*)0)->c );

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vlad Tepesch schrieb:
> eventuell wäre folgendes denkbar:
>
>
> uint32_t teilgroesseC  = sizeof( ((A*)0)->c );
> 
>
> 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)

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Grrrr schrieb:
>
uint32_t teilgroesseC  = sizeof( ((A*)0)->c );
> 
>
> 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.

Autor: Grrrr (Gast)
Datum:

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

Das sehe ich jetzt auch so.

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
typedef struct A
{
  int b;
  int c;
}A;

short i;

int main () {
  i = sizeof( ((A*)0)->c );
}

Nehme also alles zurück und behaupte das Gegenteil.

Autor: henky (Gast)
Datum:

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

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also,
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.

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"opator" ist auch nett. Meinte natürlich "Operator".

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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 );
}

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mahlzeit,

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

MfG

Autor: Thomas Pircher (tpircher) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: henky (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.