Hallo,
beim AVR Studio4 kann man ja zur "main.c"-Datei zusätzlich noch andere
Source Files hinzufügen, was ja auch oft gemacht wird.
Dazu habe ich ein paar Fragen.
Warum wird das gemacht, um das Programm übersichtlicher zu halten oder
gibt es noch andere Gründe?
Kann man einfach Funktionen in einem zusätzlichen Soure File
unterbringen und von der Main-Funktion aus aufrufen - oder gibt es
wichtige Punkte, die man vorher beachten muss?
Was ist mit Informationen zu Standardbibliotheken etc. wie z.B.
#include<stdio.h>, können die auch problemlos in einem zusätzlichen
Soure File untergebracht werden?
DMC schrieb:> Hallo,>> beim AVR Studio4 kann man ja zur "main.c"-Datei zusätzlich noch andere> Source Files hinzufügen, was ja auch oft gemacht wird.> Dazu habe ich ein paar Fragen.>> Warum wird das gemacht, um das Programm übersichtlicher zu halten oder> gibt es noch andere Gründe?
Zugegeben.
Gerade als Neuling wird es dir eher selten passieren, das deine
Codegrößen ein paar 100 Zeilen überschreiten.
Aber irgendwann ist es auch bei dir soweit, dass die Programmgrößen
zunehmen. Spätestens dann verspürst du den Drang, im Sinne der
Reibeflächen deiner Maus auf die endlosen Scrollvorgänge durch den Code
zu verzichten und statt dessen den Code nach Themenkreisen geordnet in
einzelne C-Files aufzuteilen. Zb. alle Low-Level LCD Funktionen in eine
C-Datei, in der nur diese Funktionen drinnen sind. Oder die Low-Level
UART Funktionen. Oder ...
Angenehmer Nebeneffekt: Auf die Art entsteht ganz von alleine eine
Sammlung von nützlichen Software-Baugruppen, die man ganz einfach von
einem Projekt zum nächsten übernehmen kann. Denn die LCD Ansteuerung
(eines Standard-HD44780 Text-LCD) ist ja da wie dort die gleiche.
Lediglich andere Texte werden ausgegeben.
> Kann man einfach Funktionen in einem zusätzlichen Soure File> unterbringen und von der Main-Funktion aus aufrufen - oder gibt es> wichtige Punkte, die man vorher beachten muss?
Im C-File steht die Implementierung der Funktionen.
Im H-File (dem Header) stehen die Schnittstellendefinitionen, also die
'Kennungen' der Funktionen.
Der verwendende Code includiert das Header File und kann damit die
Funktionen aufrufen. Der Compiler weiß, dass es die Funktionen gibt und
welche Parameter diese haben. Alles weitere macht dann der Linker, der
die einzelenen, bereits übersetzten Code-Blöcke zum kompletten Programm
zusammenbaut.
> Was ist mit Informationen zu Standardbibliotheken etc. wie z.B.> #include<stdio.h>, können die auch problemlos in einem zusätzlichen> Soure File untergebracht werden?
Wozu soll das gut sein?
im Header File (erkennbar an der Endung h) ist im Regelfall sowieso kein
COde direkt enthalten. Das Header File dient als Beschreibung dessen,
was an Code an anderer Stelle verfügbar ist! Aber der eigentliche Code,
der eine Funktion implementiert ist (bis auf Ausnahmefälle) da nicht
drinnen.
Danke für die ausführliche Antwort!!!
Ich verstehe es so, dass ich dann problemlos in anderen .c-Source-Files
problemlos Funktionen unterbringen kann, die dann von main.c aus
aufgerufen werden können!?!
DMC schrieb:> Danke für die ausführliche Antwort!!!>> Ich verstehe es so, dass ich dann problemlos in anderen .c-Source-Files> problemlos Funktionen unterbringen kann, die dann von main.c aus> aufgerufen werden können!?!
Problemlos? Nö. Da gibt es noch genug Probleme.
Aber für's Erste kannst Du das problemlos so als problemlos gegeben
nehmen.
Bitflüsterer schrieb:> Problemlos? Nö. Da gibt es noch genug Probleme.> Aber für's Erste kannst Du das problemlos so als problemlos gegeben> nehmen.
Dann werde ich das mal testen und der Probleme harren, die da kommen ;O)
Ich habe jetzt mal spaßeshalber eine Funktion, die Zahlen über den UART
ausschmeißt, in ein zweites Sourcefile gesteckt (uartzahl.c).
Das gab viele Fehlermeldungen.
Vor allem konnte "uint8_t" in uartzahl.c nicht mehr vom Compiler erkannt
werden.
Habe dann das #include<avr/io.h> von mai.c nach uartzahl.c rüberkopiert
und jetzt geht es.
Warum es jetzt geht, verstehe ich allerdings nicht wirklich.
DMC schrieb:> "uint8_t" in uartzahl.c nicht mehr vom Compiler erkannt> werden.
Weil uint8_t eine Definition ist, die in dem Headerfile erfolgt.
Ohne diesen Header kennt der Compiler den Typ nicht.
Schau Dir mal die io.h an, dann siehst Du es.
DMC schrieb:> Ich habe jetzt mal spaßeshalber eine Funktion, die Zahlen über den UART> ausschmeißt, in ein zweites Sourcefile gesteckt (uartzahl.c).>> Das gab viele Fehlermeldungen.>> Vor allem konnte "uint8_t" in uartzahl.c nicht mehr vom Compiler erkannt> werden.> Habe dann das #include<avr/io.h> von mai.c nach uartzahl.c rüberkopiert> und jetzt geht es.> Warum es jetzt geht, verstehe ich allerdings nicht wirklich.
Der wesentliche Verständnispunkt hier ist, dass jede C-Datei dem
Compiler einzeln vorgelegt wird. Wird die Datei uartzahl.c compiliert,
dann wird dabei nicht berücksichtigt, dass Du in der Datei main.c (oder
auch irgendeiner anderen C-Datei) schon die Zeile beginnend mit
"#include ..." eingefügt hast. Auch spielt es keine Rolle, ob und das
der Compiler (evtl. sogar unmittelbar vorher) die Datei main.c übersetzt
hat.
Jede C-Datei ist eine Einheit für sich.
Dabei spielt auch keine Rolle, ob in einer Datei eine Funktion aus einer
anderen Datei aufgerufen wird.
Karl Heinz kann das viel schöner erklären und hat auch mehr Übung darin.
:-)
Damit nun aus einer Reihe verschiedener C-Dateien, die Funktionen
enthalten (das ist mindestens main), die wiederrum Funktionen aus
anderen C-Datein enthalten sind, am Ende ein Programm herauskommt, dass
auch funktioniert, wird als letztes noch der sogenannte Linker
aufgerufen.
Wenn nämlich in einer C-Datei eine Funktion aufgerufen wird, die in
derselben C-Datei nicht enthalten ist, dann erzeugt der Compiler an der
Stelle, an der die Adresse dieser Funktion eigentlich stände (und am
Ende dann schliesslich stehen wird) einen Platzhalter.
Wenn hingegen eine C-Datei eine Funktion enthält, egal ob sie nirgends
in der selben Datei aufgerufen wird oder nicht (es sei denn sie ist
static deklariert), dann fügt der Compiler eine Information hinzu, die
vom Namen der Funktion (und den Parametern) abgeleitet einen Hinweis auf
die 'vorläufige' Adresse der Funktion hinleitet. Vorläufig, weil ja die
endgültige Adresse der Funktion im fertigen Programm zu dem Zeitpunkt
noch nicht bekannt sein kann.
Der Linker nun, ist das Programm, dass sich alle Dateien anschaut
(diese Objekt-Dateien genannten Files [oft mit der Endung o.] enthalten
wiegesagt enweder Platzhalter für Adressen von externen Funktionen
oder/und Tabellen mit den relativen Adressen von Funktionsdefinitionen.
Der Linker ersetzt, in dem er in diesen Tabellen nachschaut, die
Platzhalter durch die realen Adressen; zusätzlich berücksichtigt er aber
auch noch, wo im fertigen Programm die fraglichen Funktionen zu liegen
kommen (welche realen Adressen sie erhalten).
Vielen herzlichen Dank für die ausführlichen Erklärungen!
Das muss ich erst mal sacken lassen!
Immerhin gibt der UART in uartzahl.c mit
UDR0 = zahl;
alles klaglos aus, obwohl
der UART selber in main.c initialisiert wurde.
Ansonsten bekomme ich zu uartzahl.c eine Warnung:
return type defaults to 'int'
Die Zeile, auf die sich die Warnung bezieht, lautet:
uartausgabe(uint64_t ausgabezahl) <-- Warnung
{...; return 0;}
(nicht über die Verwendung von uint64_t wundern, ich gebe damit wirklich
große Dezimalzahlen von einem Frequenzzähler aus)
DMC schrieb:> Die Zeile, auf die sich die Warnung bezieht, lautet:> uartausgabe(uint64_t ausgabezahl) <-- Warnung
Du hast keinen Typ für den Rückgabewert angegeben, daher
> return type defaults to 'int'
Stefan Ernst schrieb:> Du hast keinen Typ für den Rückgabewert angegeben, daher>> return type defaults to 'int'
Danke für die schnelle Antwort!
Wie gibt man in dem Fall günstigerweise für Typ für den Rückgabewert an
(der ja von meiner Seite eigentlich nicht gebraucht wird)?
DMC schrieb:> Stefan Ernst schrieb:>> Du hast keinen Typ für den Rückgabewert angegeben, daher>>> return type defaults to 'int'>> Danke für die schnelle Antwort!>> Wie gibt man in dem Fall günstigerweise für Typ für den Rückgabewert an> (der ja von meiner Seite eigentlich nicht gebraucht wird)?
Jetzt ist aber dann doch die Gelegenheit für beliebten Hinweis auf ein
C-Buch gekommen.
Wenn Du keinen Wert zurückgeben willst, dann ist 'void' der Datentyp.
Prima, danke, ich entsinne mich.
Habe auch meine C-Bücher wieder rausgekramt, Danke für den Hinweis!
Noch mal zum AVR-Studio.
Dann macht es möglicherweise wenig Sinn, Dinge wie den ADC, die
PWM-Ausgabe, Interrupts oder ähnliches außerhalb von main.c zu
initialisieren (also in einer anderen verlinkten Sourcecode-c.-Datei)???
Noch mal meine Frage, macht es möglicherweise wenig Sinn, Dinge wie den
ADC, die PWM-Ausgabe, Interrupts oder ähnliches außerhalb von main.c zu
konfigurieren (also in einer anderen Source-Code-Datei als uartzahl.c)?
Oder spielt das hier keine Rolle, weil die benutzten Register (z.B.
ADMUX beim ADC) so oder so im Controller eingetragen werden?
Ich mache es normalerweise immer so, daß ich beispielsweise eine uart.c
habe, in der sich dann sämtliche Funktionen befinden, die die UART
betreffen. Unter anderem auch die Initialisierung der UART. Und mit den
anderen Baugruppen genauso, z.B. die Timer, den ADC, die SPI usw.
Das hindert dich ja dann nicht daran, die Konfiguration während des
Programmlaufes zu verändern (z.B. steigende auf fallende Flanken
umschalten und ähnliches).
DMC schrieb:> Noch mal meine Frage, macht es möglicherweise wenig Sinn, Dinge wie den> ADC, die PWM-Ausgabe, Interrupts oder ähnliches außerhalb von main.c zu> konfigurieren (also in einer anderen Source-Code-Datei als uartzahl.c)?>> Oder spielt das hier keine Rolle, weil die benutzten Register (z.B.> ADMUX beim ADC) so oder so im Controller eingetragen werden?
Letzteres. Es spielt technisch gesehen keine Rolle, in welcher C-Datei
welche Funktion steht (in Bezug auf die Behandlung von Peripherie).
Die Tatsache, dass man mehrere C-Dateien zu einem Programm zusammenfügen
kann, wird im allgemeinen dazu genutzt, etwa alle ADC-relevanten
Funktionen, alle PWM-relevanten Funktionen etc. in eigene Dateien
zusammenzufassen. Das gilt für die Initialisierungsfunktionen genauso
wie für Funktionen die das Resultat auslesen, den PWM-Duty-Cylce
verändern oder ähnliches.
Die jeweiligen Interrupt-Funktionen für ADC, PWM etc. kann man auch
einzeln in die jeweilige Datei schreiben. Dafür spricht, dass fast immer
auch Variablen beteiligt sind, die etwa den ADC-Wert aufnehmen und die
vorzugsweise in der Datei definiert werden sollte in der auch die
restlichen ADC-relevanten Funktionen enthalten sind.
Das alles sind allerdings keine festen Regeln. Wichtiger ist fast, dass
man überhaupt eine Ordnung hat. Aber das spielt natürlich auch alles
erst eine Rolle, wenn die Projekte grösser werden. Wenn etwa ein
ADC-Wert nur an einer Stelle z.B. ausgegeben wird, dann wäre es
überflüssig ordentlich, diese Variable nun in einer besonderen Datei zu
definieren. Genauso, ist es nicht wirklich nötig, die
Initialisierungsfunktion für den UART auszulagern, wenn das die einzige
Peripherie ist, die man überhaupt nutzt.
Allenfalls ergeben sich solche Fälle wenn man schon einen Satz an
C-Dateien hat, den man für andere Projekte verwendet hat. Dann braucht
man das alles nicht erst umzukopieren.
P.S. Sinn wird nicht "gemacht". Etwas hat einen Sinn oder nicht.
Vielen herzlichen Dank für die ausführliche Antwort!!!
Bitflüsterer schrieb:> Die Tatsache, dass man mehrere C-Dateien zu einem Programm zusammenfügen> kann, wird im allgemeinen dazu genutzt, etwa alle ADC-relevanten> Funktionen, alle PWM-relevanten Funktionen etc. in eigene Dateien> zusammenzufassen.
Das ist ein guter Ansatz, werde das auch so versuchen für die Zukunft.
Bitflüsterer schrieb:> Die jeweiligen Interrupt-Funktionen für ADC, PWM etc. kann man auch> einzeln in die jeweilige Datei schreiben. Dafür spricht, dass fast immer> auch Variablen beteiligt sind, die etwa den ADC-Wert aufnehmen und die> vorzugsweise in der Datei definiert werden sollte in der auch die> restlichen ADC-relevanten Funktionen enthalten sind.
Also wie bei main.c außerhalb des Funktionsblocks?!
Für ein Interrupt benötigt man volatile Variablen, wenn sie außerhalb
des Interrupts verwendet werden sollen (so weit ich weiß). Wo ist dann
der Vorteil?
Bitflüsterer schrieb:> P.S. Sinn wird nicht "gemacht". Etwas hat einen Sinn oder nicht.
Da hast du wahr!
Sinn ist eine digitale Größe wie 0 und 1:
0 = Unsinn
1 = Sinn
;O)
DMC schrieb:> Vielen herzlichen Dank für die ausführliche Antwort!!!> Bitflüsterer schrieb:>> Die jeweiligen Interrupt-Funktionen für ADC, PWM etc. kann man auch>> einzeln in die jeweilige Datei schreiben. Dafür spricht, dass fast immer>> auch Variablen beteiligt sind, die etwa den ADC-Wert aufnehmen und die>> vorzugsweise in der Datei definiert werden sollte in der auch die>> restlichen ADC-relevanten Funktionen enthalten sind.>> Also wie bei main.c außerhalb des Funktionsblocks?!
So ungefähr. Jedenfalls nicht lokal in einer Funktion. (Es gibt aber
andererseits auch sinnvolle Anwendungen von Funktionslokalen Variablen.
Ich erwähne das nur der vollständigkeit halber und empfehle das Studium
der Abschnitte über Variablen-Lebensdauer resp. Scope).
> Für ein Interrupt benötigt man volatile Variablen, wenn sie außerhalb> des Interrupts verwendet werden sollen (so weit ich weiß). Wo ist dann> der Vorteil?
Ich hoffe ich verstehe die Frage richtig: Es geht darum, die Variablen
zu den Funktionen passend zu gesellen. So ist etwa, der in einer ISR
ausgelesene AD-Wandlungswert ein Beispiel für einen volatile Variable,
die man in dem C-File, mit der ISR definieren könnte. Meiner Meinung
nach, sollte man das auch so tun, auch wenn die Variable noch in anderen
Dateien gelesen wird. Das ist zu einem gewissen Grad willkürlich aber
nicht eigentlich unsinnig. Strenge Argumente gibt es nicht dafür.
Technisch ginge es auch andersherum.
Noch mal Danke für die ausführlichen Antworten und guten Erklärungen!
Ja, ich meinte es so mit den Variablen in einer ISR.
Noch mal ein kleiner Sprung zurück:
1
voiduartausgabe(uint64_tausgabezahl)
2
{...;return0;}
Nachdem ich jetzt in uartzahl.c der Funktion ein "void" verpasst habe,
ergibt sich nun in main.c eine Warnung beim Compilieren, die bei "Built"
aber wieder verschwindet:
warning: implicit declaration of function 'uartausgabe'
Kann man feststellen, woran das liegt?
> Kann man feststellen, woran das liegt?
Es ist ja schon festgestellt. Die Feststellung wird Dir als Warnung
ausgegeben.
Du hast irgendwo einen Widerspruch. Die Warnung bezieht sich auf eine
bestimmte Zeile. Diese Zeile musst Du Dir anschauen. Und bei dieser
spezifischen Warnunge alle anderen Stellen an denen der Funktionsname
erscheint. Ausserdem die Reihenfolge.
Alle Deklarationen, Definitionen und Verwendungen müssen konsistent
sein. Z.B. ist es sinnlos in einer Funktion die 'return'-Anweisung mit
eine Parameter zu verwenden, wenn die Funktion selbst mit 'void'
definiert ist, denn das heisst ja das sie keinen Wert zurückgibt.
Nirgendwo sonst darf diese Funktion bzw. deren Verwendung implizit oder
explizit einen Rückgabewert festlegen oder erwarten. Aktiviere am besten
mit -Wall alle Warnungen.
Die Warnungen sind eigentlich (in der Regel) genügend aussagekräftig.
Aber man muss schon ein wenig Englisch können oder eben bei Leo oder im
Wörterbuch nachschauen. Dann auch ggf. im C-Buch.
warning: implicit declaration of function 'uartausgabe'
Auf Deutsch: Implizite Deklaration der Funktion 'uartausgabe'
Jetzt muss man wissen, was eine "Implizite Deklaration" ist. Das steht
im C-Buch. Im wesentlichen heisst dass, das der Compiler, wenn Du beim
Aufruf oder der Deklaration oder der Definition den Rückgabetyp nicht
ausdrücklich nennst (dazu zählt auch void), ein 'int' annimmt.
Danke für die Erklärungen!!!
Dazu habe ich zwei Fragen.
1. Warum muss man bei void (also wenn kein Rückgabewert gewollt ist)
trotzdem den Rückgabetyp angeben.
2. Wie kann man konkret Abhilfe schaffen, damit der Compiler keine
Warnung diesbezüglich mehr ausgibt?
Bitflüsterer schrieb:> Aktiviere am besten> mit -Wall alle Warnungen.
Schon geschehen!
DMC schrieb:> 1. Warum muss man bei void (also wenn kein Rückgabewert gewollt ist)> trotzdem den Rückgabetyp angeben.
Weil an dieser Stelle das Schlüsselwört 'void' nun mal genau diese
Bedeutung hat.
Etwas weiter ausgeholt hat das ganze historische Gründe. Im ganz frühen
C war die Sache so, dass der Compiler für so gut wie alles was er nicht
kannte, erst mal den Datentyp int annehmen musste.
'void' als Kennung für 'nichts bestimmtes' ist erst sehr viel später
Sprachbestandteil geworden.
> 2. Wie kann man konkret Abhilfe schaffen, damit der Compiler keine> Warnung diesbezüglich mehr ausgibt?
Indem man die Ursache abstellt.
Eine implizite Deklaration einer Funktion tritt an der verwendenden
Stelle auf. Wenn das dein Code ist
1
intmain()
2
{
3
uart_init();
4
}
und der Compiler keinen Protoypen der Funktion vor der Verwendung der
Funktion präsentiert bekommen hat, dann muss er die Funktion 'implizit
deklarieren'. D.h. er muss Annahmen treffen. Eine dieser Annahmen ist
zb, dass eine Funktion einen int zurückliefert.
Diese Annahme kann richtig sein, sie kann aber auch falsch sein. Daher
warnt dich der Compiler.
Die Warnung kann man also auch so übersetzen:
Hör mal. Ich soll da eine Funktion aufrufen. Aber ich weiß nichts von
der Funktion. Daher geh ich mal mit den Standardannahmen an die Sache
ran, auch wenn die falsch sein mögen. Kontrollier das bitte und am
besten präsentierst du mir vor der Verwendung der Funktion erst mal
einen Funktionsprotoypen, dann brauch ich nicht raten.
In deinem Fall, in dem der Protoyp der Funktion im Header File uart.h
steht
1
#ifndef UART_H_INCLUDED_
2
#define UART_H_INCLUDED_
3
4
voiduart_init(void);
5
6
#endif
bedeutet das, das du einfach einen entsprechenden #include in dein File
reinmachst
1
#include"uart.h"
2
3
intmain()
4
{
5
uart_init();
6
}
dann wird dem Compiler der Protoyp der Funktion präsentiert, ehe es zum
Funktionsaufruf kommt, der Compiler kennt dann die Signatur der Funktion
und muss nicht mehr mit Standardannahmen raten -> die Warnung ist weg.
Ein anderer Fall, der aber ganz ähnlich gelagert ist, ist ein ganz
einfaches Reihenfolgeproblem.
Der Compiler liest den Quellcode von oben nach unten. Und zwar nur ein
einziges mal.
Hast du im Code
1
voidfoo()
2
{
3
bar();
4
}
5
6
voidbar()
7
{
8
}
dann hast du ein ähnlich gelagertes 'implicite declration' Problem.
Von oben nach unten gelesen erfolgt die Verwendung der Funktion (also
der Aufruf) bevor die Funktion definiert wird. Der Compiler kann also
zum Zeitpunkt des Funktionsaufrufs noch nicht wissen, wie die Funktion
bar aussieht. Die wird ja erst danach definiert.
Die Abhilfe ist einfach. Es gibt 2 Möglichkeiten.
* Dreh die Reihenfolge der Funktionen um
1
voidbar()
2
{
3
}
4
5
voidfoo()
6
{
7
bar();
8
}
so dass die Signatur der Funktion bar bekannt ist, noch ehe im Quelltext
der Aufruf der Funktion erfolgt.
* Oder aber:
präsentier dem Compiler einen Prototypen für die Funktion vor der
Verwendung der Funktion
1
voidbar(void);
2
3
voidfoo()
4
{
5
bar();
6
}
7
8
voidbar()
9
{
10
}
Letzten Endes liegt bei einer 'implicite declaration' die immer gleiche
Ursache vor: Eine Funktion wird verwendet, von der die Aufrufsignatur
nicht bekannt ist (wieviele Argumente nimmt die Funktion, welchen
Datentyp haben die Argumente, wie ist der Returntyp der Funktion). Stell
das ab und die Warnung verschwindet. Das das eine Warnung ist und kein
echter Fehler hat historische Ursachen und ist dem konservativen
Vorgehen der Normungsgremien geschuldet, die nur sehr ungern wesentliche
Sprachbestandteile ändern, wenn das bedeutet, das alter Code (selbst
wenn er falsch war) dadurch nicht mehr compilieren würde.
DMC schrieb:> Danke für die Erklärungen!!!>> Dazu habe ich zwei Fragen.>> 1. Warum muss man bei void (also wenn kein Rückgabewert gewollt ist)> trotzdem den Rückgabetyp angeben.
Falls Du einen Compiler nach und einschliesslich C99 benutzt ist
implizite Deklaration ohnehin nicht mehr erlaubt. Du musst grundsätzlich
den Typ des Rückgabewertes angeben. Selbst als das noch erlaubt war, hat
das kaum einer so gemacht.
Das habe ich schon erklärt. Ergänzend kannst Du mal im Kernighan &
Ritchie, 2. Auflage ANSI C, S. 71 nachschauen. Aber beachte: Das ist ein
alter Standard. Das ist nur noch zur Erläuterung, worum es sich handelt.
> 2. Wie kann man konkret Abhilfe schaffen, damit der Compiler keine> Warnung diesbezüglich mehr ausgibt?
Es ist sehr davon abzuraten, Warnungen abzustellen oder zu ignorieren,
falls das Dein Hintergedanke ist. Für den Anfänger gilt das, meiner
Ansicht nach, auf jeden Fall!
Bitflüsterer schrieb:> Es ist sehr davon abzuraten, Warnungen abzustellen oder zu ignorieren,> falls das Dein Hintergedanke ist. Für den Anfänger gilt das, meiner> Ansicht nach, auf jeden Fall!
Auf jeden Fall.
Für den Profi hingegen gilt: setz den Warning-Level so hoch wie es nur
geht. Du willst jede Warnung haben, damit du die Ursache im Code finden
und abstellen kannst.
(ok, bei ein paar Warnungen hat insbesondere Microsoft meiner Meinung
nach ein wenig übertrieben, die stell ich auch einzeln ab. Aber generell
gilt gerade für Profis: Warning Level rauf. Warnings werden wie Fehler
behandelt und müssen im Code korrigiert werden. Produktionscode muss
komplett ohne Fehler (eh klar) und Warnungen compilieren.
Karl Heinz schrieb:> Bitflüsterer schrieb:>>> Es ist sehr davon abzuraten, Warnungen abzustellen oder zu ignorieren,>> falls das Dein Hintergedanke ist. Für den Anfänger gilt das, meiner>> Ansicht nach, auf jeden Fall!>> Auf jeden Fall.> Für den Profi hingegen gilt: setz den Warning-Level so hoch wie es nur> geht. Du willst jede Warnung haben, damit du die Ursache im Code finden> und abstellen kannst.
Huch? Das ist doch das was ich meinte!
Ich rate in meinem Beitrag davon ab, die Warnungen abzustellen. Und die
implizite Einschränkung bei Nicht-Anfängern ist, auch enthalten, wenn
auch nicht so ausgeführt wie bei Dir.
> bei ein paar Warnungen ..., die stell ich auch einzeln ab
Was genau bewog Dich zu Deinem Beitrag?
Ach. Ich glaube ich ahne was. Du meinst den Default-Warn-Level.
Naja. Ich habe noch im Kopf gehabt, dass ich dem TO hier:
Beitrag "Re: AVR Studio4: Sourcefile zufügen, was beachten?" geraten habe mit
-Wall alle Warnungen einzuschalten.
@ TO:
Dazu muss man wissen, dass per Default nicht alle Warnungen aktiviert
sind. Wenn ich geschrieben habe, dass man keine Warnungen abstellen oder
ignorieren soll, dann habe ich vorausgesetzt, dass alle Warnungen
angestellt sind.
Bitflüsterer schrieb:> Ach. Ich glaube ich ahne was. Du meinst den Default-Warn-Level.
Ja, genau.
Ich wollte nur unterstreichen, dass die Sache mit dem Ignorieren oder
gar Abstellen von Warnungen nicht nur für Anfänger gilt.
So quasi nach dem Muster: Als Anfänger nimmst du alle Warnungen mit.
Später, wenn du dann besser wirst, lockerst du das Ganze wieder.
Das spielt es so nicht. Auch Profis legen sich die Warning Latte so
hoch, wie sie nur können. Und das aus gutem Grund.
Naja. Um recht zu behalten müsste ich jetzt belegen, dass das für Profis
nur bedingt gilt. Aber das tust Du ja schon selbst, in dem Du schreibst,
das Du einige Warnungen durchaus abstellst. Und was anderes habe ich ja
auch nicht geschrieben.
Der Satz "Für den Anfänger gilt das, meiner Ansicht nach, auf jeden
Fall!"
bedeutet ja nicht, das es für Profis auf keinen Fall gilt, sondern das
es für Profis in gewissen Fällen nicht gilt.
Vielen Dank für die professionellen Antworten!!!
DMC schrieb:> 2. Wie kann man konkret Abhilfe schaffen, damit der Compiler keine> Warnung diesbezüglich mehr ausgibt?
Das sollte bedeuten:
Wie kann man die Ursache ausräumen, damit der Compiler keine
Warnung diesbezüglich mehr ausgibt?
Im Moment reden reden wir, glaube ich, teilweise etwas aneinander
vorbei.
Die Funktion
>>uartausgabe(uint64_t ausgabezahl)
befindet sich in der Datei
>>uartzahl.c
(also in einer.c-Datei und nicht in einer .h-Datei).
Kann ich jetzt dem Compiler mitteilen ... (s.u.) ?
1
#ifndef UARTZAHL_C_INCLUDED_
2
#define UARTZAHL_C_INCLUDED_
3
4
voiduartausgabe(void);
5
6
#endif
Karl Heinz schrieb:> Die Abhilfe ist einfach. Es gibt 2 Möglichkeiten.> * Dreh die Reihenfolge der Funktionen um>>void bar()> {> }>> void foo()> {> bar();> }> so dass die Signatur der Funktion bar bekannt ist, noch ehe im Quelltext> der Aufruf der Funktion erfolgt.
Das ist hier nicht das Mittel der Wahl, weil die genannte Funktion ja in
einer anderen .c-Datei stehen soll.
Karl Heinz schrieb:> * Oder aber:> präsentier dem Compiler einen Prototypen für die Funktion vor der> Verwendung der Funktion>>void bar( void );>> void foo()> {> bar();> }>> void bar()> {> }
Das mit der Prototypenpräsentation für die Funktion klingt gut!
Schreibt man diese Präsentation
>>void uartausgabe( void );
normalerweise einfach in den "leeren" Raum zwischen Header und
main-Funktion?
DMC schrieb:> Schreibt man diese Präsentation>>>void uartausgabe( void );> normalerweise einfach in den "leeren" Raum zwischen Header und> main-Funktion?
Nein. Man schreibt sie in eine H-Datei und inkludiert die H-Datei am
Anfang der C-Datei.
Jeder der eine Funktion aus einer anderen C-Datei aufrufen will,
inkludiert die zu dieser C-Datei gehörende, gleichnamige H-Datei. Dort
stehen alle Prototypen der Funktionen, die sich in in der C-Datei
befinden.
Nebenbemerkung: Die H-Datei inludiert man auch in die dazugehörige
C-Datei. Damit kann der Compiler überprüfen, ob der Prototyp auch mit
der richtigen Funktionsdefinition übereinstimmt und andernfalls davor
warnen.
DMC schrieb:> Vielen Dank für die professionellen Antworten!!!>> DMC schrieb:>> 2. Wie kann man konkret Abhilfe schaffen, damit der Compiler keine>> Warnung diesbezüglich mehr ausgibt?>> Das sollte bedeuten:> Wie kann man die Ursache ausräumen, damit der Compiler keine> Warnung diesbezüglich mehr ausgibt?>>> Im Moment reden reden wir, glaube ich, teilweise etwas aneinander> vorbei.
Den Eindruck habe ich auch. Denn die Frage ist Dir nun schon auf drei
verschiedene Arten von mindesten zwei verschiedenen Personen beantwortet
worden.
Was genau hast Du an: "Schreibe keine impliziten Deklarationen (d.h.
lasse den Datentyp nicht weg)" nicht verstanden?
> Die Funktion>>>uartausgabe(uint64_t ausgabezahl)> befindet sich in der Datei>>>uartzahl.c> (also in einer.c-Datei und nicht in einer .h-Datei).>>> Kann ich jetzt dem Compiler mitteilen ... (s.u.) ?>>
1
>#ifndefUARTZAHL_C_INCLUDED_
2
>#defineUARTZAHL_C_INCLUDED_
3
>
4
>voiduartausgabe(void);
5
>
6
>#endif
7
>
>
Nein. Wozu willst Du zwei widersprechende Deklarationen im Programmtext
haben? Das gibt dann Warnings. Das ist aber auch schon erwähnt worden.
>>> Karl Heinz schrieb:>> Die Abhilfe ist einfach. Es gibt 2 Möglichkeiten.>> * Dreh die Reihenfolge der Funktionen um>>>>void bar()>> {>> }>>>> void foo()>> {>> bar();>> }>> so dass die Signatur der Funktion bar bekannt ist, noch ehe im Quelltext>> der Aufruf der Funktion erfolgt.>> Das ist hier nicht das Mittel der Wahl, weil die genannte Funktion ja in> einer anderen .c-Datei stehen soll.
Das hat Karl Heinz auch nicht gemeint. Er wollte Dir klarmachen, welche
Rolle die Reihenfolge von Defintionen bzw. Deklarationen in einer
Datei bzw. in einer C- und einer H-Datei spielen.
> Karl Heinz schrieb:>> * Oder aber:>> präsentier dem Compiler einen Prototypen für die Funktion vor der>> Verwendung der Funktion>>>>void bar( void );>>>> void foo()>> {>> bar();>> }>>>> void bar()>> {>> }>> Das mit der Prototypenpräsentation für die Funktion klingt gut!
Schön.