C -> Headerfile -> Variablen und Funktionen initalisieren

OP #6033918
Lesenswert?

Halli Hallo,
habe da mal eine Frage..
Gibt es eigentlich irgendwelche Probleme wenn man Variablen ( Strukturen 
etc. ) in der Headerdatei initialisiert?
Und was spricht dagegen Funktionen „inline“  in das Headerfile zu 
implementieren?
z.B
1
extern inline enum eTimerError Timer1CompAInit( const sTimer16Config_t *psTab , void (*pFncCallback)(void) )
2
{
3
  cli(); /**< Vorsichtshalber Interrupts global sperren */
4

5
  TCCR1A  = psTab->uiWGMxx;
6
  TCCR1B  = psTab->uiWGMxx;
7
  TCCR1B  |= psTab->uiCSxx;
8
  OCR1A  = psTab->uiCnt;
9
  
10
  if ( pFncCallback == NULL )
11
  {
12
    return ERROR_TIMER_NO_ADDRESS;
13
  }else
14
  {
15
    pvTimerCallback[CALLBACK_TIMER1_COMPA] = pFncCallback;
16
  }
17
  
18
  _ENABLE_OCIE1A;
19

20
  sei();
21
  
22
  return ERROR_TIMER_OK;
23
}
Gast #6033940
Lesenswert?

Probleme mit Definitionen von Variablen (das ist die Voraussetzung für 
deren Initialisierung) und Funktionen, ergeben sich aus der Tatsache, 
dass mehrfache Definitionen nicht möglich sind und in einer 
Fehlermeldung (des Linkers) münden, falls die fragliche Header-Datei 
in mehr als eine C-Datei des selben Projekts eingefügt wird. Gerade das 
ergibt nämlich Mehrfachdefinitionen.

Das bedeutet nämlich, dass mehr als eine Objektdatei entsteht, welche 
die selben Variablen, die selben Funktionen enthalten. Eine Situation in 
welcher  der Linker sich darüber beschweren wird. Er kann nämlich nicht 
entscheiden, welche der gleich benannten Variabeln und Funktionen er 
verwenden soll.
Gast #6033950
Lesenswert?

Was das extern-Attribut einer Funktion betrifft, der die Definition auf 
dem Fusse folgt, bin ich schlicht überfragt. Ich vermute, dass eine 
Fehlermeldung aufttritt. Das folgende also mit einem Vorbehalt, dass mir 
hier ein moderner C11-"Trick" entgangen ist.

Der Sinn von "extern" ist nämlich gerade, dem Compiler mitzuteilen, dass 
die Definition an anderer Stelle, extern im Verhältnis zu der gerade 
vorliegenden Quellcodedatei, erfolgt. Plötzlich aber folgt sie doch 
direkt in der Datei.
Sowas habe ich noch nie versucht, weil es widersinnig ist, oder mir 
jedenfalls so scheint.
Entweder benutze ich eine externe Definition oder eine unmittelbare.
Beides zusammen führt auf einen Widerspruch.
#6033986
Lesenswert?

Naj H. schrieb:
> Gibt es eigentlich irgendwelche Probleme wenn man Variablen ( Strukturen
> etc. ) in der Headerdatei initialisiert?

Compiler und Linker unterscheiden grundsätzlich nicht zwischen Header- 
und Codedateien; man könnte beliebigen Code in die Header- oder 
Codedatei reintun und es funktioniert trotzdem.
Nur ist es halt üblich und hat sich so bewährt, dass man den 
eigentlichen Code in die Codedatei packt und die "Schnittstelle" dazu, 
in Form von Vorwärtsdeklarationen und Definitionen etc., in eine 
separate Headerdatei.
Dies verbessert die Übersichtlichkeit und Wiederverwendbarkeit.
Gast #6034043
Lesenswert?

Du hast da ganz unabhängig von der inline Thematik auch ein Problem in 
deiner Funktion.

Du entsperrst die Interrupts nicht wieder, falls die Funktion über 
diesen Zweig verlassen wird:
1
  if ( pFncCallback == NULL )
2
  {
3
    return ERROR_TIMER_NO_ADDRESS;
#6034106
Lesenswert?

Theor schrieb:
> Probleme mit Definitionen von Variablen (das ist die Voraussetzung für
> deren Initialisierung) und Funktionen, ergeben sich aus der Tatsache,
> dass mehrfache Definitionen nicht möglich sind und in einer
> Fehlermeldung (des Linkers) münden, falls die fragliche Header-Datei
> in mehr als eine C-Datei des selben Projekts eingefügt wird. Gerade das
> ergibt nämlich Mehrfachdefinitionen.
>
> Das bedeutet nämlich, dass mehr als eine Objektdatei entsteht, welche
> die selben Variablen, die selben Funktionen enthalten.

Das ist doch kein Problem!
man sollte nur Inhalt von *.h-Datei mit folgenden Zeilen umrahmen:
für main.h wäre das so:
1
// main.h
2
#ifndef MAIN_H
3
#define MAIN_H 
4

5
/*** Inhalt ***/
6

7

8
#endif  /* MAIN_H */

Naj H. schrieb:
> Und was spricht dagegen Funktionen „inline“  in das Headerfile zu
> implementieren?

Dagegen spricht nichts.
(Firma: @home) #6034179
Lesenswert?

Naj H. schrieb:
> Und was spricht dagegen Funktionen „inline“  in das Headerfile zu
> implementieren?

nichts, UND das ist standard in vielen projekten, die umfangreich 
konfiguriert werden.

mit optionalen code in headers kannst du auch bei viel optionalen code 
gut strukturieren und den überblick waren - eigentlich nur so.

kannst du dir quasi in jedem open source project anschauen!


mt
#6034212
Lesenswert?

Dirk B. schrieb:
> Es löst aber ncht das Problem, wenn man mehrere C-Dateien hat.

Man kann beliebig C-Dateien haben, die beliebig viele H-Dateien 
includieren. Die #def - Zeilen schutzen von mehrfachen includieren. So 
wird in einer H-Datei definierte Variable nur einmal definiert. Die 
Variablen, die nur in C-Datei definiert sind, bleiben nur in dieser 
C-Datei sichtbar, so können mehrere Variablen in verschiedenen C-Dateien 
gleich heißen.
#6034220
Lesenswert?

Maxim B. schrieb:
> Man kann beliebig C-Dateien haben, die beliebig viele H-Dateien
> includieren. Die #def - Zeilen schutzen von mehrfachen includieren. So
> wird in einer H-Datei definierte Variable nur einmal definiert. Die
> Variablen, die nur in C-Datei definiert sind, bleiben nur in dieser
> C-Datei sichtbar, so können mehrere Variablen in verschiedenen C-Dateien
> gleich heißen.

Nein.

Die Include-Guards schützen nur vor mehrfachen inkludieren in einer 
C-Datei.
Diese werden getrennt übersetzt und der Compiler legt auch jedesmal neue 
Variablen an.
Die Sichtbarkeit wird nur eingeschränkt, wenn diese als static definiert 
sind.

Wenn sie global sind (und denselben Bezeichner haben), hat der Linker 
ein Problem.
Gast #6034222
Lesenswert?

Dirk B. schrieb:
> Maxim B. schrieb:
>> Das ist doch kein Problem!
>> man sollte nur Inhalt von *.h-Datei mit folgenden Zeilen umrahmen:
>> für main.h wäre das so:
>
> Das löst nur das Problem, wenn in einer C-Datei dieser Header evtl durch
> andere Header auch/nochmal inkludiert werden.
>
> Es löst aber ncht das Problem, wenn man mehrere C-Dateien hat.

Deshalb die Funktion per
1
static inline
definieren, dann geht das.

Da inline nur ein Hint an den Compiler ist, muss man im Zweifel nochmal 
compilerspezifisch nachhelfen, um wirklich ein Inlining zu garantieren.

GCC z.B. via
1
__attribute__((always_inline))
#6034229
Lesenswert?

Dirk B. schrieb:
> Die Sichtbarkeit wird nur eingeschränkt, wenn diese als static definiert
> sind.

Nicht nur. Es reicht, eine Variable nur in einer C-Datei zu definieren 
und in keiner H-Datei. Somit wird sie nirgendwo sonst sichtbar. Noch 
besser ist diese Variable innerhalb einer Funktion zu definieren.

"static" hat etwas andere Funktion. Zwingt Compiler die Variable in RAM 
und nicht in Register oder Stack zu legen.
#6034233
Lesenswert?

x^2 schrieb:
> Deshalb die Funktion per
>
>   static inline
>
> definieren, dann geht das.
>
> Da inline nur ein Hint an den Compiler ist, muss man im Zweifel nochmal
> compilerspezifisch nachhelfen, um wirklich ein Inlining zu garantieren.
>
> GCC z.B. via
> __attribute__((always_inline))

Sobald die Funktion static ist wird es keine Konflikte mit 
Mehrfachdefinitionen mehr geben, dann ist es eigentlich auch völlig egal 
ob die betreffende Funktion inline ist oder nicht.
#6034235
Lesenswert?

x^2 schrieb:
> Da inline nur ein Hint an den Compiler ist, muss man im Zweifel nochmal
> compilerspezifisch nachhelfen, um wirklich ein Inlining zu garantieren.
>
> GCC z.B. via
> __attribute__((always_inline))

Das ist nur notwendig, wenn man unbedingt verhindern wird, daß die 
Funktion mit push und pop die Zeit verschwendet.
Wenn man einfach "inline" schreibt, wird die Entscheidung dem Compiler 
überlassen, trotzdem kann inline-Funktion ruhig in H-Datei bleiben.
Gast #6034251
Lesenswert?

Ein kleinwenig fehlt mir das Verständnis, warum versucht wird, eine 
solche Frage in einem "demokratischem Prozess" zu lösen.

Sollte man nicht besser:
1. Die jeweilig benutzte Sprachreferenz zu Rate ziehen?
2. Die Doku des verwendeten Compilers befragen?
3. Ein gutes Buch kaufen und dieses auswendig lernen?

Und dann erst, wenn dann noch was unklar ist, eine konkrete Frage 
stellen?
So richtig, mit Angabe: Welche Sprache, welcher Compiler?

Bitte nicht falsch verstehen!
Ich habe nichts gegen demokratische Prozesse. Auch nicht in Foren.
Wenn soziale Aspekte im Spiel sind, kann das durchaus der angemessene 
Weg sein.
Aber bei rein technischen Fragen?
Doch eher nicht....
#6034256
Lesenswert?

Maxim B. schrieb:
> "static" hat etwas andere Funktion. Zwingt Compiler die Variable in RAM
> und nicht in Register oder Stack zu legen.

Das sind technische Einzelheiten (der Stack liegt durchaus auch im RAM), 
die man nicht wissen muss.

static schränkt die Sichtbarkeit von Variablen und Funktionen auf die 
aktuelle C-Datei (übersetzungseinheit) ein.
#6034259
Lesenswert?

Dirk B. schrieb:
> Das sind technische Einzelheiten (der Stack liegt durchaus auch im RAM),
> die man nicht wissen muss.

Das ist aber wichtig: eine Variable in RAM macht noch verbleibende RAM 
kleiner. Eine Variable in Stack ist "RAM-Gratis".

Dirk B. schrieb:
> static schränkt die Sichtbarkeit von Variablen und Funktionen auf die
> aktuelle C-Datei (übersetzungseinheit) ein.

Das passiert auch ohne extra "static" zu schreiben.
#6034329
Lesenswert?

Maxim B. schrieb:
> Dirk B. schrieb:
>> ES geht hier um Variablen, die in Headerdateien definiert sind.
>
> Dafür gibt es schon erwähnte Abhilfe mit #ifndef - #define

Nein.

Das #ifdef kann nichts davon wissen ob die in einer anderen 
Übersetzungseinheit schonmal definiert war oder werden wird. 
Include-Guards werden verwendet um Mehrfachincludes innerhalb der 
selben Übersetzungseinheit zu vermeiden.
#6034339
Lesenswert?

Bernd K. schrieb:
> Das #ifdef kann nichts davon wissen ob die in einer anderen
> Übersetzungseinheit schonmal definiert war oder werden wird.
> Include-Guards werden verwendet um Mehrfachincludes innerhalb der
> selben Übersetzungseinheit zu vermeiden.

#ifndef hilft, H-Datei nicht mehr zu includieren, wenn sie schon einmal 
includiert wurde. Somit werden alle Variablen, die in dieser Datei 
definiert sind, nur einmal definiert.
Reicht das nicht?
#6034375
Lesenswert?

Maxim B. schrieb:
> Harry L. schrieb:
>> Maxim B. schrieb:
>>> Reicht das nicht?
>>
>> Nein!
>
> Dann kann ich nur vermuten, was dir noch stört, arbeitsfähige Code zu
> schreiben...

Hör auf zu vermuten, und lern besser C!
Sobald du die .h-Datei in einer weiteren .C-Datei includierst, knallts 
im Linker.

Der Include-Guard schützt nur einzelne Files vor Doppel-Definitionen.
#6034522
Lesenswert?

Dirk B. schrieb:
> Maxim B. schrieb:
>> Hm... Wie sonst macht man eine Variable sichtbar für mehrere C-Dateien?
>
> Man definiert sie in der C-Datei, die sie benötigt.
>
> Man deklariert sie (mit extern) in der entsprechenden Header-Datei.

Vielleicht habe ich "definiert" und "deklariert" verwechselt.
Wenn man in einer H-Datei einer Variablen gleich Wert gibt - klar wird 
Compiler schimpfen. Muß er auch.
#6034536
Lesenswert?

Eine Definition (bei C mit impliziter Deklaration) verbraucht 
Speicherplatz. Die Variable (oder Funktion wird angelegt)

Eine Deklaration gibt bekannt, dass dieser Name vorhanden ist. Reine 
Information.

Bei einer Funktionsdeklaration kann man auf das extern verzichten, da 
man dies am Fehlenden Funktionskörper erkennen kann.

Bei einer Variablendeklaration ist das extern nötig.

> Wenn man in einer H-Datei einer Variablen gleich Wert gibt - klar wird
> Compiler schimpfen.

Das wäre sogar eine Initialisierung (wenn es bei der Definition 
geschieht)
#6034547
Lesenswert?

Dirk B. schrieb:
> Eine Definition (bei C mit impliziter Deklaration) verbraucht
> Speicherplatz. Die Variable (oder Funktion wird angelegt)
>
> Eine Deklaration gibt bekannt, dass dieser Name vorhanden ist. Reine
> Information.
>
> Bei einer Funktionsdeklaration kann man auf das extern verzichten, da
> man dies am Fehlenden Funktionskörper erkennen kann.
>
> Bei einer Variablendeklaration ist das extern nötig.

Ich mache alles so einfach wie möglich. *.h - extern var ohne Wert. *.c 
- var mit Wert. static var - wenn Wert zwischen Aufrufen erhalten sein 
sollte, var aber von außen unsichtbar bleiben sollte.
Gast #6034609
Lesenswert?

Bernd K. schrieb:
> Sobald die Funktion static ist wird es keine Konflikte mit
> Mehrfachdefinitionen mehr geben, dann ist es eigentlich auch völlig egal
> ob die betreffende Funktion inline ist oder nicht.

Korrekt, so hatte ich das auch gemeint.

Maxim B. schrieb:
> Das ist nur notwendig, wenn man unbedingt verhindern wird, daß die
> Funktion mit push und pop die Zeit verschwendet.
> Wenn man einfach "inline" schreibt, wird die Entscheidung dem Compiler
> überlassen, trotzdem kann inline-Funktion ruhig in H-Datei bleiben.

Genau, das hatte ich auch geschrieben.

Wie gesagt, inline wollte der TO. Würde sonst auch wenig Sinn ergeben, 
dass er die Definition der Funktion unbedingt in den Header verschieben 
will.
#6034621
Lesenswert?

x^2 schrieb:

> Wie gesagt, inline wollte der TO. Würde sonst auch wenig Sinn ergeben,
> dass er die Definition der Funktion unbedingt in den Header verschieben
> will.

Ich habe zur Probe einige Funktionen mal so, mal so gemacht. Schreibt 
man einfach "inline", da kommt es von Aufrufzahl, ob das als inline oder 
als separate Funktion gemacht wird. Wenn mit __prefixen, dann wird immer 
inline gemacht. Manchmal spart das nicht nur Zeit, sondern auch 
Speicherplatz! Für ATMega bedeutet Funktionauruf 4 Bytes für call und 
noch 2-4-6-8... Bytes für Parameter. Oft wird inline-Funktion kürzer, da 
Daten benutzt, die schon in Register sind.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren