mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Stuct Übergabe in C


Autor: soundmachine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen,

ich bin relativ neu in der Programmierung von Cortex M0/M3 und habe eine 
Verständnisfrage zu der Verwendung von Structs.

Zuerst zum groben Aufbau meines Programmes:

Ich habe eine #include "globals.h", in der sind alle 
variablendefinitionen für meine globalen Variablen aufgestellt. Hier 
auch die Definition einer Structur.

struct Encoder
{
  int ZeitDeltaA;
  int ZeitDeltaAB;
  float Drehzahl;
  int Drehrichtung;
  int Alive;
}Drehgeber;


Die "Variable" Drehgeber kann ich nun auch überall in der main, sowie in 
diversen Interrupts verwenden. Der lesende, sowie schreibende Zugriff 
fuktioniert soweit sehr gut.


Nun habe ich eine "Motorcontrol.h", sowoe eine "Motorcontrol.c" 
geschrieben, in der ich gerne Subfunktionen für die Motorregelung 
unterbringen möchte, um mein Programm übersichtlicher zu gestalten.

•
/* Header guard */
#ifndef FUNCTIONS_H
#define FUNCTIONS_H


/* Include-Dateien, je nach Funktion (SPI, USART, GPIO, RCC)*/
#include <stdbool.h>

/* Defines */


/* Typedefs, structs, unions und enums */

//struct bla {
//  int bla;
//};

/* globale Variablen deklarationen */
//extern int bla;

/*alle  Funktionsnamen hier rein*/
bool Drehrichtung(struct Encoder test123);


#endif






//*********************************************
//**** Basis-Funktionen für Drehzahlerkennung und Motorregelung
//*********************************************
#include <MotorControl.h>

bool Drehrichtung(struct Encoder test123)
{
  return true;
} 



Mein Problem ist nun, ich möchte als Übergabeparameter eine Structur 
übergeben. Irgendwie habe ich haber hier scheinbar Verständnisprobleme.
Ganz abgesehen davon, dass Structuren noraleerweise nur über Pointer 
angebunden werden um die Laufzeit zu optimieren, scheint es so, als wenn 
er die Definition der Structur gar nicht kennen würde. Ein Aufruf in der 
Main

int main(void) {
  Setup();
  test = 0;
  test2 =0;
  while(1)
  {
if (SW2 || test>5)
  LED2On;
else LED2Off;

if (SW3 || test2 > 7 || (Drehrichtung(Drehgeber)==true))
  LED3On;
else LED3Off;

if (SW4||Drehgeber.Drehzahl >4000.0)
  LED4On;
else LED4Off;




Kommt eine Fehlermeldung, dass die bergabearumente nicht stimmen würden.


WO hab ich den Knoten im Hirn, bzw.noch Grundlagenlücken?


Bin für jede ernst gemeinte Erklärung sehr dankbar.

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soundmachine schrieb:
> Kommt eine Fehlermeldung, dass die bergabearumente nicht stimmen würden.

bitte mal die genaue Fehlermeldung posten.

Autor: MikeH (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du musst natürlich globals.h in functions.h inkludieren damit die 
Struktur dort bekannt gemacht (deklariert) wird.

Autor: Daniel A. (daniel-a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
struct Encoder wird in Motorcontrol.h im Funktionsargument als 
Incomoplete type definiert, da struct Encoder aus globals.h nicht 
definiert ist, da globals.h vorher nicht includiert wurde. An der stelle 
ist ein Incomplete type aber nicht erlaubt, und eine struct definition 
meist nutzlos.  Drehgeber wird wiederum in globals.h definiert, das ist 
der falsche Ort dafür. Entweder du teilst das auf Motorcontrol.c und 
Motorcontrol.h auf, oder du erstellst ein globals.c.

H-Datei:
/* Typedefs, structs, unions und enums */
struct Encoder
{
  int ZeitDeltaA;
  int ZeitDeltaAB;
  float Drehzahl;
  int Drehrichtung;
  int Alive;
};

/* globale Variablen deklarationen */
extern struct Encoder Drehgeber;

C-Datei:
#include <WhereverEncoderIsDefined.h>

struct Encoder Drehgeber;

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soundmachine schrieb:
> Guten Morgen,
>
> ich bin relativ neu in der Programmierung von Cortex M0/M3 und habe eine
> Verständnisfrage zu der Verwendung von Structs.
>
> Zuerst zum groben Aufbau meines Programmes:
>
> Ich habe eine #include "globals.h", in der sind alle
> variablendefinitionen für meine globalen Variablen aufgestellt. Hier
> auch die Definition einer Structur.
>
> struct Encoder
> {
>   int ZeitDeltaA;
>   int ZeitDeltaAB;
>   float Drehzahl;
>   int Drehrichtung;
>   int Alive;
> }Drehgeber;
>

Das ist normalerweise keine gute Idee. Die Typdeklaration (alles bis zu 
schließenden geschweiften Klammer) gehört tatsächlich in eine 
Header-Datei.

Das nachgestellte "Drehgeber" allerdings deklariert eine globale 
Variable vom Typ struct Encoder. Und zwar in allen .c-Dateien, die 
diesen Header einbinden. gcc (der Linker, genauer gesagt) ist zwar so 
schlau, all diese globale Variablen wieder zu einer einzigen 
zusammenzuziehen, sauber ist das aber nicht. Variablendeklarationen 
haben in Header-Dateien nichts verloren.
Dort gehört (nur) die Typdefinition hin:
struct Encoder
{
  int ZeitDeltaA;
  int ZeitDeltaAB;
  float Drehzahl;
  int Drehrichtung;
  int Alive;
};

und möglicherweise die Information, daß in irgendeiner .c - Datei eine 
globale Variable dieses Types deklariert wird:
extern struct Encoder Drehgeber;

Die Deklaration gehört dann in die .c - Datei (irgend- aber nur eine):
struct Encoder Drehgeber;


> Nun habe ich eine "Motorcontrol.h", sowoe eine "Motorcontrol.c"
> geschrieben, in der ich gerne Subfunktionen für die Motorregelung
> unterbringen möchte, um mein Programm übersichtlicher zu gestalten.
>
>
> /* Header guard */
> #ifndef FUNCTIONS_H
> #define FUNCTIONS_H
> 
> 
> /* Include-Dateien, je nach Funktion (SPI, USART, GPIO, RCC)*/
> #include <stdbool.h>
> 
> /* Defines */
> 
> 
> /* Typedefs, structs, unions und enums */
> 
> //struct bla {
> //  int bla;
> //};
> 
> /* globale Variablen deklarationen */
> //extern int bla;
> 
> /*alle  Funktionsnamen hier rein*/
> bool Drehrichtung(struct Encoder test123);
> 
> 
> #endif
> 
>
>
>
>
>
>
>
> 
> //*********************************************
> //**** Basis-Funktionen für Drehzahlerkennung und Motorregelung
> //*********************************************
> #include <MotorControl.h>
> 
> bool Drehrichtung(struct Encoder test123)
> {
>   return true;
> }
> 
> 
>

Das hat mit deinem Problem nichts zu tun, aber eine (globale) Struktur 
als Funktionsparameter zu übergeben, birgt ein paar Fallen. Die Struktur 
wird byvalue übergeben, d.h. Änderungen daran finden nur an der lokalen 
Kopie statt (die beim Verlassen der Funktion verworfen wird). Das kann 
durchaus erwünscht sein, führt aber möglicherweise zu Verwunderung.

>
> Mein Problem ist nun, ich möchte als Übergabeparameter eine Structur
> übergeben. Irgendwie habe ich haber hier scheinbar Verständnisprobleme.
> Ganz abgesehen davon, dass Structuren noraleerweise nur über Pointer
> angebunden werden um die Laufzeit zu optimieren, scheint es so, als wenn
> er die Definition der Structur gar nicht kennen würde. Ein Aufruf in der
> Main
>
>
> 
> int main(void) {
>   Setup();
>   test = 0;
>   test2 =0;
>   while(1)
>   {
> if (SW2 || test>5)
>   LED2On;
> else LED2Off;
> 
> if (SW3 || test2 > 7 || (Drehrichtung(Drehgeber)==true))
>   LED3On;
> else LED3Off;
> 
> if (SW4||Drehgeber.Drehzahl >4000.0)
>   LED4On;
> else LED4Off;
> 
> 
> 
>
>
> Kommt eine Fehlermeldung, dass die bergabearumente nicht stimmen würden.
>
>
> WO hab ich den Knoten im Hirn, bzw.noch Grundlagenlücken?
>
>
> Bin für jede ernst gemeinte Erklärung sehr dankbar.

Wo der Fehler steckt, ist daran nicht erkennbar. Poste mal die exakte 
Compiler-Fehlermeldung und die Zeilen, auf die sie verweist. 
Möglicherweise hast Du vergessen, deine Header-Datei überall dort, wo 
die Struct benutzt wird, zu includieren?

Autor: soundmachine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo...

Danke an Markus und Daniel für die sehr Ausführliche Aufstellung.

Ein Paar Fragen bleiben aber noch.

Markus F. schrieb:
> Variablendeklarationen
> haben in Header-Dateien nichts verloren.
> Dort gehört (nur) die Typdefinition hin:
> struct Encoder
> {
>   int ZeitDeltaA;
>   int ZeitDeltaAB;
>   float Drehzahl;
>   int Drehrichtung;
>   int Alive;
> };
>
> und möglicherweise die Information, daß in irgendeiner .c - Datei eine
> globale Variable dieses Types deklariert wird:
> extern struct Encoder Drehgeber;
>
> Die Deklaration gehört dann in die .c - Datei (irgend- aber nur eine):
> struct Encoder Drehgeber;


Worin liegt hier der Unterschied zu meiner Version? Mit "extern" gebe 
ich ja nicht nur bekannt, dass die Variable extern irgendwo deklariert 
wird,sondern er erstellt sie doch auch gleich. Ich muss sie nämlich 
nichtmehr in einer .c Datei deklarieren, er kennt sie durch den extern 
Aufruf und ich kann sie überall (auch in Interruptroutinen etc.) 
verwenden.
Somit ist die Variable ja doch irgendwie in der .h Datei deklariert.


Zweite Frage: Ich habe bisher alle gobalen Variablen in der "globals.h" 
errstellt. Also auch sowas wie z.B. int globaler_Zaehler.
In der Main hab ich die "globals.h" includiert und konnte dann diese 
Variable in ALLEN Funktionen, auch Interruptroutinen verwenden. Wieso 
funktioniert das bei Structuren nicht auch deckungsgleich

Dritte Frage:
Wenn die "globals.h" ausschließlich für defines und Definition von 
Strukturen gedacht ist, wo deklariere ich dann "formschön" meine ganzen 
globalen Variablen, und zwar so, dass ich sie auch wirklich überall 
verwenden kann

Autor: Dirk B. (dirkb2)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
soundmachine schrieb:
> Mit "extern" gebe
> ich ja nicht nur bekannt, dass die Variable extern irgendwo deklariert
> wird,sondern er erstellt sie doch auch gleich.

Das ist falsch.

Mit extern hast du (nur) eine Deklaration und genau die gehören in die 
.h

Die Definition gehört in eine .c Datei.

Wenn du die Variablen in der .h definierst, dann wird sie jedesmal neu 
angelegt, wenn du sie in einer .c einbindest.
Das sind dann verschiedene Variablen.
Wenn du nur eine .c in deinem Projekt hast, fällt das nicht auf.

Autor: soundmachine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Dirk,

wie wäre denn dann die eigentliche saubere Vorgehensweise globale 
Variablen anzulegen, die in allen über eine .h eingebundenen .c Dateien 
verwendet werden können

Autor: Dirk B. (dirkb2)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Die Variablen werden dort definiert, wo sie gebraucht (.c Datei) werden 
und in der entsprechenden .h datei mit extern deklariert.

Oder:
Du kannst alle globalen Variablen in einer global.c definieren und in 
einer global.h (mit extern) deklarieren.
Die global.c fügst du dann deinem Projekt hinzu, Die global.h bindest du 
mit #include dort ein, wo du die Variablen brauchst.


Speicherverbrauchender Code (Definitionen von Variablen und Funktionen) 
gehört in .c
Informierender Code (Deklarationen) gehört in .h, aber nur soweit es für 
die Nutzung der entsprechenden .c nötig ist.

Die .h beschreibt die Schnittstelle zur .c

Autor: soundmachine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Dirk,

das bedeutet aber ich könnte eine "globals.h" erstellen nach dem Muster:
extern int test1;
extern int test2;
struct teststruct
{ int a;
int b;
}


dann eine entsprechende .c Datei
extern int test1;
extern int test2;
struct teststruct hallo;


und die Header Datei kann ich dann mehrfach includieren, also z.B. in 
der Main und in meiner Motorcontrol.h-



Frage: - Ist das so richtig?
       - Wird ´beim Mehrfachinkludieren der globals.h dann die Variable 
nichta uch mehrfach angelegt, also in der main UND in der 
Motorcontrol.c?

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soundmachine schrieb:
> dann eine entsprechende .c Datei
> extern int test1;
> extern int test2;
> struct teststruct hallo;

in der c Datei, darf das extern  icht mit rein.

Autor: Dirk B. (dirkb2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soundmachine schrieb:
> Frage: - Ist das so richtig?
>        - Wird ´beim Mehrfachinkludieren der globals.h dann die Variable
> nichta uch mehrfach angelegt, also in der main UND in der
> Motorcontrol.c?

Mir schien, als wüßtest du den Unterschied zwischen Deklaration und 
Definition.

Deklaration: Bekanntgabe, dass da etwas mit dem Namen ist.
Definition: Anlegen von einem Objekt mit dem Namen.

In C beinhaltet eine Definiton auch eine Deklaration (aber nicht 
umgekehrt)

Deklarieren kannst du soviel du willst.
Definieren darfst du nur einmal.


Wenn in der .h nur Deklarationen stehen, dann sollte die Anwort klar 
sein. Oder?

Autor: soundmachine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achja... copy paste Fehler...in der C ist selbstverständlich ein extern, 
somit ist die Defnition dann an mehreren Stellen im Proramm. Die 
Deklaration nur in der globals.c

Autor: Jack (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In Beitrag "Re: Stuct Übergabe in C" geht es etwas 
Durcheinander mit Deklarationen und Definitionen. Das Meiste ist 
richtig, aber dann hat sich Markus wahrscheinlich verschrieben. Z.B. 
stimmt Folgendes nicht:

Markus F. schrieb:
> Variablendeklarationen
> haben in Header-Dateien nichts verloren.

Doch. Definitionen haben in .h nichts zu suchen.

>
> Die Deklaration gehört dann in die .c - Datei (irgend- aber nur eine):
> struct Encoder Drehgeber;

Die Definition gehört in die .c-Datei.


Daher noch mal eine einfache Definition der Begriffe:

Deklaration:

Teilt dem Compiler mit dass es irgendwo die entsprechende Variable oder 
Funktion gibt oder wie ein Datentyp aussieht. Belegt aber keinen 
Speicherplatz. Gehört, wenn sie mit anderen Teilen des Programms geteilt 
werden soll, in .h Header.

Definition:

Teilt dem Compiler mit, dass hier Speicher für eine Variable oder 
Funktion belegt werden soll. Beinhaltet nebenbei auch eine Deklaration. 
Gehört in .c Dateien, niemals in .h

Sonderfall: Globale Inline-Funktionen. Die kommen in .h Header. Aber das 
lassen wir jetzt mal.

Autor: Dirk B. (dirkb2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soundmachine schrieb:
> Achja... copy paste Fehler...in der C ist selbstverständlich ein extern,
> somit ist die Defnition dann an mehreren Stellen im Proramm. Die
> Deklaration nur in der globals.c

Lies dir das nochmal durch, denn:

Peter II schrieb:
> in der c Datei, darf das extern  icht mit rein.

Er meinte *n*icht mit rein.

Und Deklaration und Definition hat Jack auch nochmal erklärt.

Autor: soundmachine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi...hoffentlich letzte Frage:

Habe jetzt DACHTE ich, die structur soweit verstanden:

In die .h gehören nur Definitionen. Also habe ich eine .h für meine 
globalen Variablen nach folgendem Muster aufgebaut.

//*************************************************
//*** globale Variablen fuer P11
//*************************************************
#include <stdbool.h>
typedef unsigned char  u8;
typedef unsigned short u16;
typedef unsigned long  u32;

//+++ Konstanten
//const

extern int   Wert1;
extern int   Wert2;
extern int   test,test2, test3;
extern int   actSpeedRPM;
extern int   setpUserSpeed;
extern float   Ramp;

struct Encoder
{
  int ZeitDeltaA;
  int ZeitDeltaAB;
  float Drehzahl;
  int Drehrichtung;
  int Alive;
};


extern struct Encoder Drehgeber;


struct PI_Control
{
  float P_Part;
  float OutValueRamp;
  float output_value;
  bool limit_on_low;
  bool limit_on_high;
  bool Freeze;
  float I_part;
  float delta_input_last_cycle;
};

extern struct PI_Control;

extern bool I_Reset;
extern bool BaseAdjustActive;
extern int actRpm;






//*************************************************
//*** Definitionen der Port Namen ***
//*************************************************


#define    LED1On    GPIOB->BSRR = GPIO_Pin_4
#define    LED1Off    GPIOB->BRR = GPIO_Pin_4    // Oszillation MSB
#define    LED2On    GPIOB->BSRR = GPIO_Pin_5
#define    LED2Off    GPIOB->BRR = GPIO_Pin_5    // Oszillation LSB
#define    LED3On    GPIOB->BSRR = GPIO_Pin_6
#define    LED3Off    GPIOB->BRR = GPIO_Pin_6    // Zeit h(min)
#define    LED4On    GPIOB->BSRR = GPIO_Pin_7
#define    LED4Off    GPIOB->BRR = GPIO_Pin_7    // Zeit h(min)
#define    RelaisOn  GPIOB->BSRR = GPIO_Pin_15
#define    RelaisOff  GPIOB->BRR = GPIO_Pin_15  // Zeit h(min)

#define    SW1    !(GPIOB->IDR & GPIO_Pin_8)    //Switch 1
#define    SW2    !(GPIOB->IDR & GPIO_Pin_9)    //Switch 2
#define    SW3    !(GPIOB->IDR & GPIO_Pin_10)    //Switch 3
#define    SW4    !(GPIOB->IDR & GPIO_Pin_11)    //Switch 4
[c/]


Dann muss ich ja in einer .c Datei noch die Variablen wirklich Definieren. Daher habe ich eine .c Datei erstellt, die ich in mein Projek eingebunden habe....Diese sieht wiefolgt aus

[c]
//*************************************************
//*** globale Variablen fuer P11
//*************************************************
7#include "globals.h"



int   Wert1;
int   Wert2;
int   test,test2, test3;
int   actSpeedRPM;
int   setpUserSpeed;
float   Ramp;



struct Encoder Drehgeber;




struct PI_Control;
bool I_Reset;
bool BaseAdjustActive;
int actRpm;



Dann habe ich in meiner Main ein #include "globals.h" eingebunden
und in meiner Motorcontrol.h ebenfalls die "globals.h" in der Hoffnung, 
dass ich damit nun überall bekannt gemacht habe, dass es IRGENDWO noch 
diese globalen Variablen gibt, nämlich in der im Projekt hinzugefügten 
.c


Problem ist nur, dass er die Mehrfachdeklaration meiner struct scheinbar 
nicht so komisch findet. Alles mündet in folgender Fehlermeldung:


P11_Testplatine/globals.h:32:8: error: redefinition of 'struct 
PI_Control'

Autor: soundmachine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jack...sorry zu spät gelesen, daher geht bei mir Definition und 
Deklaration schon wieder durcheinander. Habs aber jetzt verstanden. Der 
Fehler bleibt weiterhin

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soundmachine schrieb:
> P11_Testplatine/globals.h:32:8: error: redefinition of 'struct
> PI_Control'

fällt dir nichts auf?
struct Encoder Drehgeber;
struct PI_Control;

Autor: soundmachine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter...Achja, der Variablennamen fehlt. Hab ich hinzugefügt. 
Fehlermeldung bleibt identisch

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soundmachine schrieb:
> @Peter...Achja, der Variablennamen fehlt. Hab ich hinzugefügt.
> Fehlermeldung bleibt identisch

an beiden stellen behoben?

Autor: soundmachine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jap,

es sieht so aus als würde er nicht damit klar kommen, dass ich die 
globals.h sowohl in der main,als auch in der Motorcontroller.h inkludert 
habe.Somit definiert es das zweimal, kann das der Fehler sein?

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soundmachine schrieb:
> .Somit definiert es das zweimal, kann das der Fehler sein?

ja, suche mal nach include guard.

Autor: Rene H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soundmachine schrieb:
> Jap,
>
> es sieht so aus als würde er nicht damit klar kommen, dass ich die
> globals.h sowohl in der main,als auch in der Motorcontroller.h inkludert
> habe.Somit definiert es das zweimal, kann das der Fehler sein?

Hast Du vielleicht ifndef / define im global.h vergessen?

Grüsse,
René

Autor: soundmachine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rene:

DAAANKE. Klar, so funktioniert es. Manchmal ist man zu blöd!

Vielen Dank allen beteiligten.

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.