Forum: Compiler & IDEs Fragen zu sizeof() in Kombination mit structs


von Josef (Gast)


Lesenswert?

Also ich bastle gerade mit Strukturen rum und bin mir ziemlich sicher, 
dass ich hier Fehler mache. Daher wäre für mich und evtl andere 
interessant was man hierbei beachten soll.

Die Größe eines "normal" angelegten Structs kann man ja anscheinend mit
1
i = sizeof(struct_Benutzer);
bestimmen.

Falls ich aber folgendes mache, mache ich dann etwas falsch?
1
typedef struct{
2
uint16_t tagnummer;                             
3
uint16_t idx; 
4
} struct_def_Benutzer;
5
6
i = sizeof(struct_def_Benutzer);

Außerdem kann ich ja noch folgendes machen:
1
typedef struct{
2
uint16_t tagnummer;                             
3
uint16_t idx; 
4
} struct_def_Benutzer;
5
6
struct_Benutzer = malloc(10 * sizeof(struct_def_Benutzer));
funktioniert das?

von yalu (Gast)


Lesenswert?

1. Frage: Nein, sizeof kann auf jeden beliebigen Datentyp angewandt
werden.

2. Frage: Ja, und wenn struct_Benutzer ein Zeiger auf die Struktur
ist, kannst du ihn anschließend ähnlich einem Arryay mit 10 Elementen
des Typs struct_def_Benutzer verwenden. So legt man dynamische Arrays
an.

von Josef (Gast)


Lesenswert?

Achso. Na gut. Ich benutze gerade in meinem Programm solche Arrays etc. 
aber anscheined mache ich etwas grundlegendes falsch. Mein µC stirbt 
leider immer, wenn ich mein Array anlege. Irgendetwas muss mit der Größe 
nicht stimmen. Hmm. Ich forsche weiter und schreibe sicher bald wieder 
was hier rein. :)

von Sven P. (Gast)


Lesenswert?

1
struct_Benutzer = malloc(10 * sizeof(struct_def_Benutzer));
ist Käse. Besser:
1
typedef struct BLABLA {...};
2
struct BLABLA *meine_var = malloc(10 * sizeof(struct BLABLA));

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Sven Pauli wrote:
>
1
> typedef struct BLABLA {...};
2
> struct BLABLA *meine_var = malloc(10 * sizeof(struct BLABLA));
3
>

Das typedef hat da nichts verloren. Wenn Du den Strukturtyp weiterhin 
als "struct BLABLA" ansprechen willst, hat das typedef keinerlei 
Funktion.

Wenn typedef, dann so:

>
1
> typedef struct {...} BLABLA;
2
> BLABLA *meine_var = malloc(10 * sizeof (BLABLA));
3
>

von Josef (Gast)


Lesenswert?

@ Sven Pauli und  Rufus t. Firefly

Also ich hab mein "struct_Benutzer" vorher schon angelegt. Will darauf 
golbal zugreifen können:
1
//im H-File
2
extern struct_def_Benutzer *struct_Benutzer;
3
//im C-File
4
struct_def_Benutzer *struct_Benutzer = 0;

Mir ist gerade aufgefallen, dass ich zwar mit
1
struct_Benutzer = malloc(10 * sizeof(struct_def_Benutzer));
die richtige Größe an Malloc() übergebe, aber ein 
sizeof(struct_Benutzer) nur '2' zurück liefert. Das wird wohl der Fehler 
sein, da ich danach wohl richtig übel einen Überlauf produziere. Aber 
warum stimmt die Größe nicht?

von holger (Gast)


Lesenswert?

Weil struct_Benutzer ein Pointer ist.

von Josef (Gast)


Lesenswert?

Achso. Dachte sizeof() kapiert das. Also dann erzeuge ich anscheinend 
doch keinen Überlauf. Hab den Fehler immer noch nicht gefunden....

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Mir ist gerade aufgefallen, dass ich zwar mit
>
> struct_Benutzer = malloc(10 * sizeof(struct_def_Benutzer));
>
> die richtige Größe an Malloc() übergebe

So und nicht anders wird das gemacht.

> (...) aber ein sizeof(struct_Benutzer) nur '2' zurück
> liefert. Das wird wohl der Fehler sein, da ich danach
> wohl richtig übel einen Überlauf produziere. Aber
> warum stimmt die Größe nicht?

Die Größe stimmt. Nur willst Du ja nicht Speicher für zehn Pointer auf 
eine Struktur anfordern, sondern Speicher für zehn Strukturen.

Also musst Du es so machen, wie eingangs bereits erwähnt.

Du solltest übrigens deutlicher voneinander zu unterscheidende 
Typnamen und Variablennamen verwenden; daß Deine Struktur fast 
genauso heißt wie die Pointervariable ist nicht hilfreich.

von Josef (Gast)


Lesenswert?

Ich hab mal ein paar Test mit anderen Funktionnen gemacht. Wenn ich 
später in einer anderen Funktion mittels struct_Benutzer[0].Name oder 
ähnlich auf meinen reservierten Speicher zugreifen, bekomme ich bei 
jedem Aufruf der Funktion einen anderen Wert. Es schaut also stark 
danach aus, dass mir der Speicher nicht reserviert wurde. Wenn ich 
jedoch unmittelbar nach dem Anlegen darauf zugreife, dann steht alles 
wunderbar drin.

Man man. Ich würde ja meinen ganzen Code mal posten, aber der ist voll 
mit anderen Sachen und eigentlich auch ganz anders. Das mit 
struct_Benutzer war nur eine Vereinfachung für den Thread hier.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Josef wrote:

> Es schaut also stark
> danach aus, dass mir der Speicher nicht reserviert wurde.

Nein, es sieht danach aus, dass ihn jemand danach überschrieben hat.
"Reservieren" kannst du ihn nur für weitere malloc(), du kannst aber
keinen Speicherplatz beim Prozessor "reservieren", auf den der dann
nicht mehr schreiben kann...

Wie andere dir schon geschrieben haben, du hast einen ziemlichen
Wirrwar in deinen Bezeichnungen, der es dir (und auch anderen ;-)
mental einfach nicht mehr erlaubt, den Überblick zu behalten.  Solange
du Typnamen vergibst, die zwar einen Zeiger definieren (dessen sizeof
bei deinem Controller offensichtlich 2 ist), die aber so heißen, als
würden sie eine ganze Struktur beinhalten, ist es kein Wunder, dass
da hinterher Speicher überschrieben worden ist, der gar nicht alloziert
worden war.

Wenn du eine Struktur allozieren willst, dann mach dir von mir aus
einen Datentyp für diese Struktur, aber alloziere dann auch die
ganze Struktur.  (Das Ergebnis der Allokation ist dann ein Zeiger
auf die Struktur.)  Wenn du 10 davon allozieren willst, dann
multipliziere das mit 10.

sizeof von einem Zeigertyp zu bilden hat in diesem Zusammenhang keinen
Sinn, sondern deutet nur darauf hin, dass du gar nicht verstanden
hast, was du da gerade tust.

von Oliver (Gast)


Lesenswert?

Auf den Inhalt eines Structs, der in einem per malloc erzeugten 
Speicherbereich liegt, kann man eigentlich nie mit
1
struct_Benutzer[0].Name
 zugreifen. Da wird immer ein Pointer mit im Spiel sein.

Mit "ungefähr so" oder "so ähnlich wie" wird das nie was.

Nur so aus Interesse: Für welches Zielsystem programmierst du 
eigentlich?

Oliver

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Auf den Inhalt eines Structs, der in einem per malloc erzeugten
> Speicherbereich liegt, kann man eigentlich nie mit
>
> struct_Benutzer[0].Name
>
> zugreifen. Da wird immer ein Pointer mit im Spiel sein.

O doch, das geht ganz genau so. Das ist der Array-Pointer-Dualismus.

Vorausgesetzt, die "sinnvoll" benannte Variable struct_Benutzer wird so 
genutzt:
1
typedef struct
2
{
3
// irgendwas
4
} struct_def_Benutzer;
5
6
7
struct_def_Benutzer *struct_Benutzer;
8
9
struct_Benutzer = malloc(10 * sizeof(struct_def_Benutzer));

von Josef (Gast)


Lesenswert?

@Oliver
du schreibst:
1
Auf den Inhalt eines Structs, der in einem per malloc erzeugten
2
Speicherbereich liegt, kann man eigentlich nie mit
3
4
struct_Benutzer[0].Name
5
6
 zugreifen. Da wird immer ein Pointer mit im Spiel sein.
Warum nicht. Das mache ich schon immer so. :) Dachte das sei auch ok so. 
Wie greife ich dann komfortabel darauf zu?
Leider muß ich hier malloc() benutzen weil ich die Größe des "Arrays" 
zur Compilerzeit nicht kenne.
PS: Was passiert eigentlich mit lokalen Arrays, dessen Größe auch zur 
Compilerzeit nicht existieren? Ich reserviere in der Funktion nämlich 
einen Buffer nammens acbuff[Filelength()]. Wobei Filelenght eben erst 
bekannt ist, wenn das Programm läuft und auf eine SD-Karte zugreifen 
kann.
PPS: Ich nutze einen AT90CAN128


@Jörg
Du hast schon recht, dass ich nicht recht weiß was ich tue. Ich versuche 
eben mit dem was ich weiß zu arbeiten. Das ich nicht wußte das sizeof() 
mit dem Pointer nicht zurückgibt was ich mir wünschte, war eben blöd 
angestellt.
Trotzdem finde ich es schon ein bißchen abwertend was da geschrieben 
wurde.

von Josef (Gast)


Lesenswert?

Ups. Zu spät die Seite aktualisiert.
Danke  Rufus t. Firefly. Dachte schon....

von Josef (Gast)


Lesenswert?

Also ich weiß echt nicht mehr weiter.
Nachdem ich in meiner Funktion mit malloc mein Array abgespeichert habe 
und diese Funktion (ohne free) wieder verlassen habe, existieren meine 
Werte noch "kurz".
Ich gehe jetzt davon aus, dass mir dieser Speicherbereich "gehört". Und 
da ich ja meine Pointervariable als extern angelegt habe, sollte diese 
doch auch noch existieren.
Wenn ich aber später die Adresse in meinem Pointer anschaue, dann ist 
das garnicht mehr die, die mir malloc() in meiner Unterfunktion 
übergeben hat.

Warum?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Wenn ich aber später die Adresse in meinem Pointer anschaue, dann ist
> das garnicht mehr die, die mir malloc() in meiner Unterfunktion
> übergeben hat.
>
> Warum?

Weil irgendwas den Pointer überschreibt?

Wie und wo ist denn der Pointer deklariert?

Wie wäre es mit Sourcecode?

von Josef (Gast)


Lesenswert?

OK. Hier mal mein Programm mit all seiner Unschönheit :)
Ich weiß das ist nicht so geschrieben, dass es schnell für jeden 
nachvollziebar ist, aber soll ja auch für mich sein. ;)
1
//Header
2
#ifndef _sd_parser_h
3
#define _sd_parser_h
4
5
#include "data_types.h"
6
7
//Flags
8
#define    FTAG  0
9
#define   FIDX  1
10
#define    FSUBIDX  2
11
#define    FANZ  3
12
#define    FATTR  4
13
#define    FCOMPL  5
14
15
16
17
18
/*return codes:  0 = EXIT_SUCCESS
19
                1 = FAILURE
20
                2 = SD Card not present, Data not present.
21
                3 = Already parsed. Please restart!
22
                4 = Only std. values loaded?
23
                5 = Read error
24
                9 = Malloc() / Speicher Fehler
25
*/
26
int app_object_parser(void);
27
28
extern can_object_directory_sd_struct *obj_dir_app;
29
30
#endif
1
//C File
2
#include <stdint.h>
3
#include <math.h>
4
#include <string.h>
5
#include <avr/pgmspace.h>
6
#include <stdlib.h>
7
#include "sd_parser.h"
8
#include "object_dir.h"
9
#include "DOS/dos.h"
10
#include "DOS/dir.h"
11
#include "logger.h"
12
13
14
can_object_directory_sd_struct *obj_dir_app = 0;
15
16
int state_flag = FTAG;
17
18
19
int app_object_parser(void)
20
{
21
  int bsdready = 0;
22
  int line = 0;
23
  //SD Initialisierung
24
  MMC_IO_Init();
25
  if(GetDriveInformation() != F_ERROR){
26
    bsdready = 1;
27
    Fclose();
28
    Chdir("/");
29
  }  
30
  else bsdready = 0;
31
  
32
  //obj_dir_app[] erstellen
33
  uint8_t lines = 0;
34
  
35
  if(bsdready==0)
36
  {
37
       if(obj_dir_app != 0) free(obj_dir_app);
38
      obj_dir_app = malloc(sizeof(obj_dir_std)+sizeof(can_object_directory_sd_struct));      //Größe + Terminierung
39
      rs232_puti(obj_dir_app);
40
      if(obj_dir_app == 0) return 9;                                       
41
      int lastline = ((sizeof(obj_dir_std)+sizeof(can_object_directory_sd_struct)+1)  / sizeof(can_object_directory_sd_struct))-1;                            
42
      obj_dir_app[lastline].tagnummer   = 0;
43
      obj_dir_app[lastline].idx          = 0x0000;
44
      obj_dir_app[lastline].Psubidx      = 0x00;
45
      obj_dir_app[lastline].subidx      = 0;
46
      obj_dir_app[lastline].attr        = 0x00;
47
      obj_dir_app[lastline].data_lenght  = 0;
48
      obj_dir_app[lastline].data        = 0;    
49
  }
50
  else if(Fopen("app_par.csv",F_READ)==F_OK)
51
  {
52
    unsigned char inbuff[Filelength()];
53
    if(sizeof(inbuff) != Filelength()){
54
      return 9;
55
      }
56
    if(Fread(inbuff,Filelength()) != Filelength()) return 5;
57
    int i = 0;
58
    while((Filelength()-i) != 0)
59
    {  
60
      if(inbuff[i] == '\n') lines++;
61
      i++;
62
    }
63
    //leeres obj_dir_app[] erstellen
64
    if(obj_dir_app != 0) free(obj_dir_app);
65
    //+x für die Standartwerte+Ende
66
    obj_dir_app = malloc( (lines+(sizeof(obj_dir_std)/sizeof(can_object_directory_sd_struct))+1) * sizeof(can_object_directory_sd_struct));
67
    if(obj_dir_app == 0) return 9;
68
    Fclose();
69
  }
70
  else return 5;
71
  //in obj_dir_app die Standartwerte einfügen
72
  while( line < (sizeof(obj_dir_std)/sizeof(can_object_directory_sd_struct)) )
73
  {
74
    obj_dir_app[line]  = obj_dir_std[line];
75
    line++;           
76
  }    
77
  if(!bsdready) return 4;
78
79
  //CSV auf SD-Karte einlesen
80
  if(Fopen("app_par.csv",F_READ)==F_OK)
81
  {                  
82
    int pos = 0;
83
    int prevpos = 0;
84
    unsigned char inbuff[10];//Filelength()];
85
    if(Fread(inbuff,Filelength()) != Filelength()) return 5;
86
    //Parser
87
    while(state_flag != FCOMPL)
88
    {
89
      while(!(inbuff[pos] == ';' || inbuff[pos] == '\r')) 
90
        pos++;
91
      if(state_flag == FTAG)
92
      {
93
        int x = pos;
94
        uint16_t num16buff = 0;
95
        while((x-prevpos-1)>=0)
96
        {
97
          num16buff = num16buff + (inbuff[prevpos+pos-x] - 48) * (int)( pow(10,(x-prevpos-1) )+0.5 );            //ACHTUNG: double pow(x,y)
98
          x--;
99
        }
100
        obj_dir_app[line].tagnummer = num16buff;  
101
        state_flag = FIDX;
102
      }
103
      
104
      else if(state_flag == FIDX)
105
      {
106
        int x = pos;
107
        uint16_t num16buff = 0;
108
        while((x-prevpos-1)>=0)
109
        {
110
          num16buff = num16buff + (inbuff[prevpos+pos-x] - 48) * (int)( pow(10,(x-prevpos-1) )+0.5 );    
111
          x--;
112
        }
113
        obj_dir_app[line].idx= num16buff;
114
        state_flag = FSUBIDX;
115
      }
116
      
117
      else if(state_flag == FSUBIDX)
118
      {
119
        int x = pos;
120
        uint8_t num8buff = 0;
121
        while((x-prevpos-1)>=0)
122
        {
123
          num8buff = num8buff + (inbuff[prevpos+pos-x] - 48) * (int)( pow(10,(x-prevpos-1) )+0.5 );    
124
          x--;
125
        }        
126
        obj_dir_app[line].Psubidx = num8buff;
127
        state_flag = FANZ;
128
      }
129
      
130
      else if(state_flag == FANZ)
131
      {
132
        int x = pos;
133
        int num8buff = 0;
134
        while((x-prevpos-1)>=0)
135
        {
136
          num8buff = num8buff + (inbuff[prevpos+pos-x] - 48) * (int)( pow(10,(x-prevpos-1) )+0.5 );    
137
          x--;
138
        }
139
        obj_dir_app[line].subidx=num8buff;
140
        state_flag = FATTR;
141
      }
142
      
143
      else if(state_flag == FATTR)
144
      {
145
146
        if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_NULL", 14) == 0)
147
          obj_dir_app[line].attr=0x00;
148
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_RO", 12) == 0)
149
          obj_dir_app[line].attr=0x01;
150
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_WO", 12) == 0)
151
          obj_dir_app[line].attr=0x02;
152
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_RW", 12) == 0)
153
          obj_dir_app[line].attr=0x03;
154
        
155
        //zur nächsten Zeile springen und wieder von Anfang
156
        //oder Ende der Datei
157
        if(pos+2 >= Filelength()) state_flag = FCOMPL;
158
        else 
159
        {
160
          state_flag = FTAG;
161
          line++;
162
        }
163
      }
164
      pos++;
165
      if(state_flag == FTAG)
166
        prevpos = pos+1;
167
      else
168
        prevpos = pos;
169
    }    
170
    Fclose();
171
    //Listenende markieren
172
    line++;
173
    obj_dir_app[line].tagnummer   = 0;
174
    obj_dir_app[line].idx          = 0x0000;
175
    obj_dir_app[line].Psubidx      = 0x00;
176
    obj_dir_app[line].subidx      = 0;
177
    obj_dir_app[line].attr        = 0x00;
178
    obj_dir_app[line].data_lenght  = 0;
179
    obj_dir_app[line].data        = 0;    
180
    return 0;
181
  }
182
  else return 5;  
183
}

von Josef (Gast)


Lesenswert?

Ahhh. Das Problem lag erstmal hier:
1
unsigned char inbuff[10];//Filelength()];
hab versehentlich das richtige mal auskommentiert um was zu testen. 
Leider hab ichs nie wieder rückgängig gemacht :(

Jetzt hab ich festegestellt, dass alles läuft bis auf die Pasage mit 
strncmp.
Das die Adresse stand einen Wert zu hoch, also das "+1" weg und schon 
war die Tabelle gut. Leider passiert hier etwas böses:
1
if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_NULL", 14) == 0)
2
          obj_dir_app[line].attr=0x00;
3
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_RO", 12) == 0)
4
          obj_dir_app[line].attr=0x01;
5
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_WO", 12) == 0)
6
          obj_dir_app[line].attr=0x02;
7
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_RW", 12) == 0)
8
          obj_dir_app[line].attr=0x03;
Immer wenn ich hier die Funktion strncmp() oder memcmp() benutze, dann 
läuft was über...

von Karl H. (kbuchegg)


Lesenswert?

Hmm.

Wenn inbuff als Array der Länge 10 definiert ist, dann
kann doch der Text DATA_ATTR_NULL gar nicht drinn stehen,
denn das sind ja schon 14 Zeichen (ohne abschliessendes '\0').

Also entweder ist der Text falsch, oder (was wahrscheinlicher ist),
die Arraygröße mit 10 ist viel zu klein.

von Josef (Gast)


Lesenswert?

Ja. Tut mir leid. Wie oben beschrieben habe ich das mal fälschlich zu 
testzwecken definiert. das muss ein Array der Größe Filelength() sein, 
damit ist dann die ganze Datei in dem Array.
Aber leider funktioniert strncmp und memcmp nicht. Dort stirbt mein 
Programm.  Das es kein echter String ist, weiß ich aber da ich ja 
sowieso nur eine bestimmte Anzahl von Zeichen prüfe, sollte die 
Nullterminierung egal sein, oder?

PS: Wenn ich inbuff[Filelength] definiere, laufe ich dann hier auch 
Gefahr der Speicherfragmentierung?

von Josef (Gast)


Lesenswert?

PPS: muss natürlich inbuff[Filelength()] heißen

:)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> PS: Wenn ich inbuff[Filelength()] definiere, laufe ich dann hier auch
> Gefahr der Speicherfragmentierung?

Nein, das ist eine automatische Variable, und die wird auf dem Stack 
angelegt.

von Josef (Gast)


Lesenswert?

Aber Filelength() (Größe der Datei auf der SD Karte) liefert ja erst zur 
Laufzeit einen Wert... Woher weiß der Compiler dann wie groß die sein 
muß?

von Karl H. (kbuchegg)


Lesenswert?

Josef wrote:
> Aber Filelength() (Größe der Datei auf der SD Karte) liefert ja erst zur
> Laufzeit einen Wert... Woher weiß der Compiler dann wie groß die sein
> muß?

Gar nicht.

Seit einiger Zeit geht das in C. Man kann Arrays dynamisch zur
Laufzeit in der Größe festlegen.

Wie der Compiler das genau realisiert, kann ich nicht sagen.
Er könnte es durch eine Stackpointer Manipulation zwischendurch
machen, oder er könnte auch auf malloc() ausweichen. Wenn ich
raten müsste, dann würde ich auf letzteres tippen, weil diese
Stackallokierung bei mehreren dynamischen Arrays sonst in ein
Problem ausarten könnte. Der Weg über malloc() ist dann doch
deutlich einfacher: Für das Array wird ein Pointer am Stack
angelegt, für die Allokierung wird ein malloc() gemacht und
in jedem Pfad der zum Verlassen des Arrays führt wird der
korrespondierende free() gemacht.  Ist aber nur eine Vermutung.

Aber eines steht auf jeden Fall fest: Wenn nicht genug Speicher
für das Array vorhanden ist, dann gibts Probleme.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

GCC hat diese Möglichkeit schon sehr lange gehabt in Form der Funktion
alloca().  Die gleiche Mimik wird (und wurde auch schon sehr lange,
ist aber mit C99 erst offiziell geworden) auch für dynamische Arrays
benutzt.

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.