Forum: Mikrocontroller und Digitale Elektronik auf struct's in Funktion zugreifen


von struct.urschwach (Gast)


Lesenswert?

Hallo,

ich habe ein paar Startschwierigkeiten mit "structs"

Folgendes habe ich in folgenden Dateien:

_________________________________________________
main.h:

struct T_Ringbuffer
{
char Soll;
char Ist;
char Buffer[RINGBUFFERGROSSE];
};

volatile extern struct T_Ringbuffer TX_Ringbuffer;

________________________________________________
uart.h:

volatile extern struct T_Ringbuffer TX_Ringbuffer;

________________________________________________
uart.c:

void shift_to_uart_tx_buffer(struct T_Ringbuffer *TX_Ringbuffer)
{
TX_Ringbuffer.Soll = 5; //(hierauf bezieht sich die Errormeldung)
}
________________________________________________

Fehlermeldung:
Error[Pe154]: expression must have struct or union type


Frage:
Was muss ich ändern, damit die Funktion in der uart.c das struct 
verarbeiten kann...?

mfg und danke schonmal im voraus.

von Björn B. (elmo)


Lesenswert?

Dein *TX_Ringbuffer ist ja ein Zeiger. Darauf greifst du nicht mit "." 
zu, sondern mit "->".

Also:
TX_Ringbuffer->Soll = 5;

von Ralf (Gast)


Lesenswert?

Du übergibst einen Pointer auf die Struktur.
Probier mal TX_Ringbuffer->Soll = 5 bzw. *TX_Ringbuffer->Soll = 5

Kann's leider grad nicht nachprüfen, aber ich meine, dass bei 
struct-Zugriffen über Pointer das '->' anstelle des '.' zum Tragen 
kommt.

Ralf

von nktion (Gast)


Lesenswert?

TX_Ringbuffer->Soll ist lediglich eine bequemere Schreibweise
für (*TX_Ringbuffer).Soll

'.' bindet stärker als '*'.

von struct.urschwach (Gast)


Lesenswert?

Danke für die Hilfe, funktioniert.

kann ich nun die Schlussfolgerung ziehen, dass es grundsätzlich zwei 
Fälle gibt,

Fall 1 wäre die Übergabe eines Pointers in der Funktion, der auf das 
struct zeigt.
In diesem Fall müsste ich
TX_Ringbuffer->Soll=5;
geschrieben werden


und Fall 2 wäre eine Funktion, die in etwa so aussehen würde:

void(struct structtyp meinstruct)
{
meinstruct.element = 10;
}

und ohne pointer arbeitet?

Ist das so korrekt?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

struct.urschwach schrieb:
> und Fall 2 wäre eine Funktion, die in etwa so aussehen würde:
>
> void(struct structtyp meinstruct)
> {
> meinstruct.element = 10;
> }
>
> und ohne pointer arbeitet?
>
> Ist das so korrekt?

Nein. Dieser zweite Fall erzeugt beim Aufruf eine Kopie des Arguments, 
verändert die Kopie und wirft sie beim Verlassen der Funktion wieder 
weg.

Das nennt sich "call-by-value".

von Karl H. (kbuchegg)


Lesenswert?

struct.urschwach schrieb:

> Ist das so korrekt?

Im Prinzip ja - es gilt 2 Fälle zu unterscheiden.

Es ist völlig analog zum Fall
1
void foo1( int i )
2
{
3
  i = 5;
4
}


und
1
void foo2( int * i )
2
{
3
  *i = 5;
4
}

im ersten Fall bekommt die Funktion einen int als Kopie und kann diese 
Kopie innerhalb der Funktion ändern wie sie lustig ist. Der Aufrufer 
kriegt davon nichts mit, denn ...  er hat ja nur eine Kopie seines 
Wertes an die Funktion weitergegeben
1
int main()
2
{
3
  int k = 8;
4
  foo1( k );    // k wird sich durch die Zuweisung in foo nicht ändern
5
}

Im zweiten Fall, gibt aber der Aufrufer die Adresse seiner eigenen 
Variablen an die Funktion. Wenn daher die Funktion dort den Wert über 
die Adresse ändert (genau das macht der * in *i = 5;), dann ändert sie 
die Variable des Aufrufers
1
int main()
2
{
3
  int k = 8;
4
  foo2( &k );   // hier greift die Funktion, mithilfe der Adresse auf
5
                // das k des Aufrufers durch. foo2 verändert k!
6
}


Und mit structs ist das auch nicht anders. Vom Mechanismus her völlig 
identisch. Ersetze "int" durch "struct T_Ringbuffer" und du hast wieder 
die beiden Fälle.

Mit dem einen kleinen Problem, dass man
1
void foo3( struct T_Ringbuffer * buf )
2
{
3
  (*buf).Soll = 5;
4
}

schreiben müsste (es geht um die Klammern)

Da das aber auf dauer mühsam ist, hat man für (*x).y eine andere 
Schreibweise eingeführt, die x->y lautet. Also kann man anstelle des 
Klammergewusels schreiben
1
void foo3( struct T_Ringbuffer * buf )
2
{
3
  buf->Soll = 5;
4
}

und hat genau dasselbe.



Sagt denn da dein C-Buch nichts darüber? Eigentlich sollte das eine 
nicht unbeträchtliche Anzahl von Seiten in deinem C-Buch einnehmen!

von struct.urschwach (Gast)


Lesenswert?

...also schonmal vielen Dank für die Antworten, aber irgendwo läuft es 
immernoch nicht ganz so, wie gewünscht... ich denke ich bräuchte für den 
Aufruf des structs in meiner Funktion nochmal einen Denkanstoss, bzw. 
ich fürchte, dass ich das struct ev. falsch deklariert bzw. definiert 
haben könnte...

Folgende Fehlermeldung gibt es beim Compilieren:
1
Error[Pe167]: argument of type "struct T_Ringbuffer" is incompatible with parameter of type "struct T_Ringbuffer *"


Dies ist der Code sowie die Aufteilung auf die beteiligten Header- und 
C-Dateien:


main.h
1
struct T_Ringbuffer
2
{
3
char Soll;
4
char Ist;
5
char Buffer[RINGBUFFERGROSSE];
6
};
7
  
8
extern volatile struct T_Ringbuffer TX_Ringbuffer;



main.c:
1
#include "main.h"
2
#include "uart.h"
3
4
5
volatile struct T_Ringbuffer TX_Ringbuffer = {0,0, };
6
7
...
8
9
int main(void)
10
{
11
...
12
13
char Text[] = {"name"};
14
        
15
add_string_to_uart_tx_buffer(TX_Ringbuffer, Text);
16
17
...
18
}




uart.h
1
volatile extern struct T_Ringbuffer TX_Ringbuffer;
2
3
void add_string_to_uart_tx_buffer(struct T_Ringbuffer* TX_Ringbuffer, char* stringarray);



uart.c
1
#include "uart.h"
2
#include "main.h"
3
4
void add_string_to_uart_tx_buffer(struct T_Ringbuffer* TX_Ringbuffer, char* stringarray)
5
{
6
  char zeiger = 0;
7
  
8
  do
9
  {
10
   TX_Ringbuffer->Soll++;
11
   if(TX_Ringbuffer->Soll < RINGBUFFERGROSSE)
12
     {;}
13
   else
14
   {  
15
     TX_Ringbuffer->Soll = 0;
16
   }
17
 
18
   TX_Ringbuffer->Buffer[TX_Ringbuffer->Soll] = stringarray[zeiger];
19
   zeiger++;
20
  }while(stringarray[zeiger] != '\0');
21
}

von Karl H. (kbuchegg)


Lesenswert?

struct.urschwach schrieb:


> Folgende Fehlermeldung gibt es beim Compilieren:
>
1
> Error[Pe167]: argument of type "struct T_Ringbuffer" is incompatible
2
> with parameter of type "struct T_Ringbuffer *"
3
>

Na dann schau dir die Teile an. Der Compiler ist da eh schon sehr 
spezifisch:

* Die Funktion will einen Pointer.
  Einen struct T_Ringbuffer *
* Der Aufrufer veruscht aber ein Objekt reinzustopfen.
  Es möchte einen struct T_Ringbuffer übergeben.

void foo( int * i )
{
  ...
}

int main()
{
  int j;

  foo( j );
}


wenn foo einen Pointer will, dann kann man nicht j reingeben ('das 
Objekt reinstopfen') sondern man muss zb. die Adresse von j übergeben

int main()
{
  int j;

  foo( &j );
}

von ronny (Gast)


Lesenswert?

YEAH, C RULEZ!

: Wiederhergestellt durch User
von Karl H. (kbuchegg)


Lesenswert?

ACh Ronny. Halt doch einfach mal die Klappe. Kein Mensch kann was dafür, 
dass du für C zu dämlich bist.
Das man eine Programmiersprache auch lernen muss, ist jetzt nicht 
wirklich wahsinnig überraschend. Und auch nicht, das das nicht von heute 
auf morgen geht.

von struct.urschwach (Gast)


Lesenswert?

hm also es ist ja nicht so, dass ich die Fehlermeldungen nicht 
übersetzen kann, nur manchmal fixt man ein Problem und es entsteht 
dadurch ein neues.

Also ich habe jetzt mal den Aufruf abgeändert zu:
1
add_string_to_uart_tx_buffer(&TX_Ringbuffer, Text);

Dies hat aber erstmal eine weitere Fehlermeldungen hervorgerufen:
1
Error[Pe167]: argument of type "struct T_Ringbuffer volatile *" is incompatible with parameter of type "struct T_Ringbuffer *"

...Eine Lösung für dieses Problem habe ich zur Abwechslung mal selber 
finden können... wenn ich die "volatile" aus dem Code komplett entferne, 
wird das Programm durchcompiliert...

Da ich aber in meinen (noch nicht implementierten) 
Interrupt-Serviceroutinen ebenfalls auf die Werte aus dem struct 
zugreifen möchte, hatte ich bisher versucht, diese Variablen volatile zu 
halten...

von Decius (Gast)


Lesenswert?

Das folgende:
extern volatile struct T_Ringbuffer TX_Ringbuffer;

in uart.h und main.h so geht das nicht, zumal du beide Headerdateien in 
main.c einbindest. Stichwort doppelte Deklaration. Nimm diese Zeile aus 
den Headerdateien heraus. und schreibe folgfendes:

main.c:
volatile struct T_Ringbuffer TX_Ringbuffer;

usart.c:
extern volatile struct T_Ringbuffer TX_Ringbuffer;

Man kann das auch über compileranweisungen wie #ifdef #else in den 
header dateien lösen. Aber ich denke mal , der weg oben ist erstmal 
leichter.

von Decius (Gast)


Lesenswert?

main.c:
volatile struct T_Ringbuffer TX_Ringbuffer;

definiert die Struktur.
------------------------------------------------------

usart.c:
extern volatile struct T_Ringbuffer TX_Ringbuffer;

verweist den linker auf die definition in main.c

--------------------------------------------------------

von Decius (Gast)


Lesenswert?

wollte schreiben deklariert die struktur. die struktur selbst wir in 
main.h definiert.

von struct.urschwach (Gast)


Lesenswert?

1
 
2
allen einen herzlichen Dank für die Hilfestellungen!

von struct.urschwach (Gast)


Lesenswert?

...eine Frage fällt mir im Anschluss nun doch noch ein:

Die Funktion
1
void add_string_to_uart_tx_buffer(struct T_Ringbuffer* TX_Ringbuffer, char* stringarray)
2
3
TX_Ringbuffer->Buffer[0] = 5;
4
stringarray[0] = 5;

arbeitet ja nun mit zwei Zeigern.
Ein Zeiger auf struct Ringbuffer und ein Zeiger auf ein stringarray.
Mit beiden Codezeilen verändere ich die Inhalte der Arrays.

Warum aber muss ich bei dem Funktionsaufruf das "normale" Array nicht 
mit der Adresse ansprechen, bei dem struct jedoch schon?



1
char* meinarray[3] = {0,2,5};
2
3
...
4
int main(void)
5
{
6
...
7
add_string_to_uart_tx_buffer(&TX_Ringbuffer, meinarray)
8
...
9
return 0;

Im Anschluss an diese Funktion ist global meinarray[0] == 5, obwohl dort 
nicht mit der Adresse gearbeitet wurde...

mfg

von Karl H. (kbuchegg)


Lesenswert?

struct.urschwach schrieb:

> Warum aber muss ich bei dem Funktionsaufruf das "normale" Array nicht
> mit der Adresse ansprechen, bei dem struct jedoch schon?

Weil Arrays anders sind.
Arrays werden niemals als Kopie übergeben, sondern immer indem die 
Startadresse des Arrays übergeben wird. Steht der Name eines Arrays 
alleine (d.h. ohne Indexangabe), dann ist damit immer die Adresse des 
Arrays gemeint. (Einzige Ausnahme: sizeof)

Jetzt muss ich mich nochmals wundern. Sagt denn dein C-Buch darüber 
nichts?
(Wenn du keines hast, dann lass dir gesagt sein: Du wirst eines 
brauchen. Diese beiden Dinge hier sind die Spitze eines Eisbergs und 
noch vergleichsweise simpel. Da warten noch viele Dinge auf dich, die du 
lernen musst. Dein C-Buch kennt die Dinge und erklärt sie dir.)



> char* meinarray[3] = {0,2,5};
du meintest
char meinarray[3] = {0,2,5};

von struct.urschwach (Gast)


Lesenswert?

du meintest
char meinarray[3] = {0,2,5};

richtig.

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.