Forum: Mikrocontroller und Digitale Elektronik ANSI C Programmierung große Struktur


von ARM (Gast)


Lesenswert?

Guten Tag, Wenn ich hier völlig falsch ist, dann entschuldige ich mich.
Ich programmiere mit uVision von KEIL auf einem LPC2134 von NXP.

Ich habe folgendes vor:
Ein große Struktur die viele Variablen speichert wird deklariert.
Mit Hilfe von diversen Funktionen wird die Struktur manipuliert.
Eine Funktion speicher einen Wert in der Struktur, die andere liest 
diesen Wert aus und eine anderer Funktion speichert einen neuen Wert 
usw.

Ist meine Lösung ok?
Wie mache ich das am besten?

Hier habe ich noch einige Fragen zum Verständnis:

1. Es wird ein Pointer auf die Struktur deklariert.
struct mstp_port_struct *mstp_port;
Das heißt doch es gibt einen Zeiger von Typ (Datentyp) der Struktur, 
aber dieser weiß nicht wohin er zeigen soll, weil er nicht initialiseirt 
wurde?

2. Es wird eine Variablen  definiert:
struct mstp_port_struct test;
Die Variable test ist von dem Typ der Struktur und enthält alle 
Variablen die in der Struktur stehen.
Ich könnte auch diese Variable an die Funktion übergeben, weil aber die 
Funktion groß ist, wird ein Zeiger übergeben, welche die Adresse von 
Strukturvariablen hat.


3.Die beiden Variablen:
struct mstp_port_struct *mstp_port;
struct mstp_port_struct test;

wurden vor main definiert und sind damit global in main reserviere ich 
Speicher und weiße die Adresse von Test dem Pointer zu.
Ist es ok wenn ich die Variablen global definiere?
Denn durch diese Zuweisung: mstp_port_struct wird Speicher in der Größe 
von struct reserviert und der Speicher ist ja kanpp?

4. in main() rufe ich Funktionen aus und übergeben mstp_port (die 
Adresse des Pointers)

5. Diesen Aufruf habe ich abgequckt auf einem Beispiel, welches genau 
meine Aufgabe realisiert:
void mstp_create_frame ( volatile struct mstp_port_struct *mstp_port )
Was hat dieser volatile für ein Zweck hier?

6. Da aber der Pointer global ist, kann ich auch die Funktionen ohne 
Parameter aufrufen:
    mstp_create_frame ( void );
    MSTP_Receive_Frame_State_Machhine( void
und die Stuktur auf folgende weise manipulieren:
void MSTP_Receive_Frame_State_Machhine( void )
{
    if (mstp_port->receive_frame_state == 
MSTP_RECEIVE_STATE_FRAME_HEADER )
   {
     printf("\n%d", mstp_port->destination);
     printf("\n%d", mstp_port->receive_frame_state);
   }
also mit Parametern und Argumenten oder mit void?



VIELEN DANK IM VORAUS.
1
#include "stdafx.h"
2
#include <stdlib.h>
3
#include <string.h>
4
5
typedef enum
6
{
7
   MSTP_RECEIVE_FRAME_STATE_IDLE =               0,
8
   MSTP_RECEIVE_STATE_FRAME_PREAMBLE =         1,
9
   MSTP_RECEIVE_STATE_FRAME_HEADER =            2,
10
   MSTP_RECEIVE_STATE_FRAME_HEADER_CRC =         3,
11
   MSTP_RECEIVE_STATE_FRAME_DATA =            4,
12
   MSTP_RECEIVE_STATE_FRAME_DATA_CRC =         5
13
} MSTP_RECEIVE_FRAME_STATE;
14
15
16
struct mstp_port_struct 
17
{
18
   MSTP_RECEIVE_FRAME_STATE receive_frame_state;
19
   unsigned char preamble1;
20
   unsigned char preamble2;
21
   unsigned char frame_type1;
22
   unsigned char destination;
23
   unsigned char source;
24
};
25
struct mstp_port_struct *mstp_port;
26
struct mstp_port_struct test;
27
 
28
29
void MSTP_Receive_Frame_State_Machhine( volatile struct mstp_port_struct *mstp_port );
30
void mstp_create_frame ( volatile struct mstp_port_struct *mstp_port );
31
32
int main (void)
33
{
34
         memset(mstp_port, 0, sizeof(struct mstp_port_struct));
35
    mstp_port = &test;
36
    mstp_create_frame ( mstp_port );   
37
    MSTP_Receive_Frame_State_Machhine( mstp_port ); 
38
    return 0;
39
    free(mstp_port);
40
}
41
42
void mstp_create_frame ( volatile struct mstp_port_struct *mstp_port )         
43
{
44
45
   mstp_port->receive_frame_state = MSTP_RECEIVE_STATE_FRAME_HEADER;   
46
   mstp_port->preamble1 =       55;
47
   mstp_port->preamble2 =       255;
48
   mstp_port->frame_type1 =       0;
49
   mstp_port->destination =       80;
50
   mstp_port->source =          81;
51
   printf("\n%d", mstp_port->destination);
52
}
53
54
55
56
void MSTP_Receive_Frame_State_Machhine( volatile struct mstp_port_struct *mstp_port )
57
{
58
    if (mstp_port->receive_frame_state == MSTP_RECEIVE_STATE_FRAME_HEADER ) //mstp->receive_frame_state steht was falsches. Da sollte eigentlich 2 stehen (MSTP_RECEIVE_STATE_FRAME_HEADER =            2)
59
   {
60
     printf("\n%d", mstp_port->destination);
61
     printf("\n%d", mstp_port->receive_frame_state);
62
   }
63
}

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


Lesenswert?

mstp_port brauchst du eigentlich gar nicht, du kannst stattdessen
auch durchweg "&test" schreiben.

Außerdem ist es verwirrend, einen Funktionsparameter genauso zu
benennen wie eine globale Variable (auch wenn sie hier letztlich
das gleiche bezeichnen).  Das erledigt sich aber von selbst, wenn
du das globale mstp_port wegwirfst.

von ARM (Gast)


Lesenswert?

Hilfe!
Die Funktion  MSTP_Interface_Init(); wird aufgerufen und dort wird ein 
Zeiger auf die Struktur deklariert und mit malloc wird diesem Zeiger 
Speicherplatz reserviert.
Muss hier noch mit einer sturct variablen noch initialisiert werden oder 
wird es mit malloc erledigt?
Nun wird die Adresse des zeigers an andere Funktion übergeben.

Das Programm lässt sich kompelieren und wenn ich in debug modus gehe, 
dann kann ich nicht durchsteppen. Klammere ich die Anweisung mit malloc 
aus, verschwindet das Problem.

Ich arbeite mit uVision von Keil. Hab mein code in Studio ausprobiert 
und es klappte.

Wo kann das Problem liegen?

Ich will die Adresse des Pointers an diverse Funktionen übergeben, wo 
dann die Struktur manipuliert wird.
1
struct mstp_iface_struct  
2
{
3
  unsigned char preamble1;
4
  unsigned char preamble2;
5
  unsigned char frame_type1;
6
  unsigned char destination;
7
  unsigned char source;
8
            
9
};
10
11
12
void MSTP_Interface_Init( void );
13
void MSTP_Master_Node_State_Machine ( struct mstp_iface_struct *mstp_ptr );
14
int main ()
15
{
16
    MSTP_Interface_Init();
17
}
18
19
void MSTP_Interface_Init( void )
20
{
21
  struct mstp_iface_struct *mstp_struct_ptr;
22
  mstp_struct_ptr = ( struct mstp_iface_struct *)malloc (sizeof(      struct  mstp_iface_struct) );
23
24
25
  mstp_struct_ptr->preamble1 = 5;
26
  MSTP_Master_Node_State_Machine ( mstp_struct_ptr );
27
}
28
29
void MSTP_Master_Node_State_Machine ( struct mstp_iface_struct *mstp_ptr )
30
{ 
31
  mstp_port->.....
32
}

von Karl H. (kbuchegg)


Lesenswert?

ARM schrieb:
> Hilfe!
> Die Funktion  MSTP_Interface_Init(); wird aufgerufen und dort wird ein
> Zeiger auf die Struktur deklariert und mit malloc wird diesem Zeiger
> Speicherplatz reserviert.

Nitpicking: Ausdrucksweise!

Es wird im Speicher Platz für ein Struktur-Objekt reserviert und die 
Adresse dieses Speicherbereichs der Pointer Variablen zugewiesen.

> Muss hier noch mit einer sturct variablen noch initialisiert werden oder
> wird es mit malloc erledigt?

malloc reserviert nur Speicher.
Sonst nichts.

>
> Das Programm lässt sich kompelieren und wenn ich in debug modus gehe,
> dann kann ich nicht durchsteppen.

Ungewöhnlich.
Im C Code gibt es dahingehend kein Problem.
Wie muss man sich das vorstellen, 'kann nicht durchsteppen'?

> Ich will die Adresse des Pointers an diverse Funktionen übergeben, wo
> dann die Struktur manipuliert wird.

Aber du willst doch sicherlich nicht alles innerhalb einer Funktion 
abhandlen, die MSTP_Interface_Init() heißt. Irgendwann wirst du doch 
auch dieses Interface ausserhalb dieser Funktion benötigen, oder nicht?

Dieses Objekt zur Laufzeit mittels malloc anzulegen, ist keine so 
wahnsinnig gute Idee (ausser du weißt jetzt noch nicht, ob du da 5 oder 
10 oder 20 oder 100 derartige Interface Objekte benötigst). Lass das 
Interface Objekt immer vorhanden sein, so gross ist das nicht. Der 
Overhead und Speicherverschnitt, den du mit dem malloc erzeugst, dürfte 
größer sein, als wenn du einfach immer ein Interface Objekt rumliegen 
hast, es aber nicht benutzt.

von Klaus W. (mfgkw)


Lesenswert?

Neben malloc() gibt es auch noch calloc().
Die Funktion ist praktisch identisch, initialisiert aber zusätzlich
den reservierten Bereich mit Nullbytes.

von ARM (Gast)


Lesenswert?

Also wenn ich in Debug Modus gehedann ist einfach die Buttens Run, Step 
usw. ausgegraut. Es sich so aus, als auf RUN gedruckt wurde und das 
Programm häng sich auf. Ich kann aber auf Stop gehen. Einen Breakpoint 
auf int main (void) setzen und wenn ich das Pogramm ausführe, dann wird 
nicht zu diesem Breakpoint gesprungen.

Ich benötige nur einen solchen Object!
Dieser wird in MSTP_Interface_Init() initialisiert und in andren 
Funktionen werden die Variablen innerhalb des Struktur-Objektes 
manipuliert.

Ich habe das auf folgende Weise gelöst;
Zwei globale Variablen deklariert:
  struct mstp_iface_struct *mstp_struct_ptr;
  struct mstp_iface_struct struct_ptr;

und in der Funktion MSTP_Interface_Init() habe ich durch:
mstp_struct_ptr =&struct_ptr den Pointer initialisiert.
Soll ich besser &struct_ptr oder mstp_struct_ptr an andere Funktionen 
übergeben?
Mit &struct_ptr wird doch die komplette Struktur übergegeben
und mit mstp_struct_ptr nur die Adresse von der Struktur.

Jetzt kann ich auf den mstp_struct_ptr schreiben und in anderen 
Funktionen stehen die geänderte Werte zu Verfügung.

Zum Verständnis:
struct mstp_iface_struct *mstp_struct_ptr;
mstp_struct_ptr = ( struct mstp_iface_struct *)malloc (sizeof( 
struct  mstp_iface_struct) );
dann kann ich doch auch auf mstp_struct_ptr schreiben
mstp_struct_ptr->irgendwas = 200;
und anderen funktionen übergeben func ( mstp_struct_ptr )

von Karl H. (kbuchegg)


Lesenswert?

ARM schrieb:
> Also wenn ich in Debug Modus gehedann ist einfach die Buttens Run, Step
> usw. ausgegraut.

Interessant.
Da scheint im Debugger was nicht zu funktionieren, sobald in der 
Runtime-Lib die dynamische Speicherverwaltung dazugelinkt wird.

> Ich benötige nur einen solchen Object!

Dann leg dieses eine auch statisch an.

> Dieser wird in MSTP_Interface_Init() initialisiert und in andren
> Funktionen werden die Variablen innerhalb des Struktur-Objektes
> manipuliert.
>
> Ich habe das auf folgende Weise gelöst;
> Zwei globale Variablen deklariert:
>   struct mstp_iface_struct *mstp_struct_ptr;
>   struct mstp_iface_struct struct_ptr;

Die Pointer Variable brauchst du nicht.
Trägt nur zur Verwirrung bei und verbraucht zusätzlichen Speicher

> Soll ich besser &struct_ptr oder mstp_struct_ptr an andere Funktionen
> übergeben?

ja.

> Mit &struct_ptr wird doch die komplette Struktur übergegeben

Nein.
&  ist der Adressof-Operator.
Er liefert die Speicheradresse des Objektes auf den er angewendet wird.
Was anderes hast du hier

  mstp_struct_ptr = &struct_ptr;

ja auch nicht gemacht: Die Speicheradresse von struct_ptr in 
mstp_struct_ptr abzulegen.


> Zum Verständnis:
> struct mstp_iface_struct *mstp_struct_ptr;
> mstp_struct_ptr = ( struct mstp_iface_struct *)malloc (sizeof(
> struct  mstp_iface_struct) );
> dann kann ich doch auch auf mstp_struct_ptr schreiben
> mstp_struct_ptr->irgendwas = 200;
> und anderen funktionen übergeben func ( mstp_struct_ptr )

Machs dir doch nicht so schwer.
Leg ein statisches MSTP Objekt an und gut ists. In Funktionen übergibst 
du die Adresse dieses Objekts, sodass die Funktionen über diese Adresse 
auf das Objekt zugreifen können. Allerdings erhebt sich die Frage: Wenn 
es sowieso immer nur 1 derartiges Objekt gibt, und alle Funktionen 
sowieso immer nur auf dieses 1 Objekt zugreifen, wozu sollen sie dann 
die Adresse davon bekommen. Sie wissen doch ohnehin in welchem MSTP 
Objekt gearbeitet werden muss.

Aber was solls
1
struct mstp_iface_struct 
2
{
3
   MSTP_RECEIVE_FRAME_STATE receive_frame_state;
4
   unsigned char preamble1;
5
   unsigned char preamble2;
6
   unsigned char frame_type1;
7
   unsigned char destination;
8
   unsigned char source;
9
};
10
11
struct mstp_iface_struct mstp_port;
12
13
void MSTP_Master_Node_State_Machine ( struct mstp_iface_struct * the_port )
14
{ 
15
  the_port->.....
16
}
17
18
void MSTP_Interface_Init()
19
{
20
  mstp_port.preamble1 = 5;
21
  MSTP_Master_Node_State_Machine ( &mstp_port );
22
}
23
24
int main ()
25
{
26
    MSTP_Interface_Init();
27
}

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


Lesenswert?

Karl heinz Buchegger schrieb:

> Die Pointer Variable brauchst du nicht.

Das schrob ich bereits im ersten Followup ganz oben.  Mir scheint's
aber, dass unser OP keinerlei Plan davon hat, was er eigentlich macht
und nun versucht, das alles per trial & error zu erledigen.  Das wird
nicht gut gehen.

Ohne wenigstens die Grundlagen verstanden zu haben, wie C mit Zeigern
umgeht und welche Rolle dabei der Adressoperator sowie die Dereferen-
zierung spielen, wirst du wohl auf keinen grünen Zweig kommen.

von Karl H. (kbuchegg)


Lesenswert?

Jörg Wunsch schrieb:
> Karl heinz Buchegger schrieb:
>
>> Die Pointer Variable brauchst du nicht.
>
> Das schrob ich bereits im ersten Followup ganz oben.

Habs gesehen. Aber anscheinend glaubt er das nicht.

> Ohne wenigstens die Grundlagen verstanden zu haben, wie C mit Zeigern
> umgeht und welche Rolle dabei der Adressoperator sowie die Dereferen-
> zierung spielen, wirst du wohl auf keinen grünen Zweig kommen.

Yep.
Ich hab auch schon oft bemerkt, dass die Leute nach dem Muster vorgehen: 
Die Funktion will einen Pointer haben, also brauch ich erst mal eine 
Pointervariable.
Drum bin ich meistens so erpicht darauf, streng zwischen den Begriffen 
Adresse und Pointer zu unterscheiden. Eine Adresse ist ein Wert, der in 
einem Pointer gespeichert wird. Die Funktion will dann gar keinen 
Pointer haben, sondern eine Adresse. Und plötzlich löst sich dann der 
ganze gordische Knoten ganz von alleine auf. Ich hab eine Adresse, die 
krieg ich mit & und die Funktion will eine Adresse (welche dann während 
der Funktionsausführung in einem Pointer gespeichert wird), passt also 
perfekt.

von ARM (Gast)


Angehängte Dateien:

Lesenswert?

Vielen Dank für eure Beiträge.
Ich habs mit der Adressübergabe realisiert, ist wirklich viel einfacher.
Vielen Dank.

Ich will was ähnliches realisieren siehe Anhang.
Und dort wird ein Adresse der Stuctur der Pointervariablen übergeben.
(siehe mstp.h ganz unter).

von ARM (Gast)


Lesenswert?

Übrigens

das Problem mit malloc() lag bei mir im Heap.
Der wurde mit 0 Bytes angegeben, die Struktut benötigt aber 12 Bytes.
Aber auch wenn ich nur 9 Bytes dem Heap zuweise, klappt's.
Kommisch.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

ARM schrieb:
> Übrigens
>
> das Problem mit malloc() lag bei mir im Heap.
> Der wurde mit 0 Bytes angegeben, die Struktut benötigt aber 12 Bytes.
> Aber auch wenn ich nur 9 Bytes dem Heap zuweise, klappt's.
> Kommisch.

Malloc braucht immer Heap. Wenn µVision, dann bitte im Startup-File (ev. 
zum Config-Wizard umschalten) die entsprechende Menge Heap reservieren. 
Sonst kann der Schuss nach hinten losgehen.

Es gibt auch Funktionen (z.B. fprintf) die ohne heap nicht immer 
auskommen, da kann man auch in ne böse Falle treten.


VG,
/th.

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.