moin zusammen Erstens bin Anfänger in C :) Wie verschiebe ich den Code von 2 Funktionen die sich in einer Headerdatei befinden in eine andere Datei (Bsp.: in die Datei meineDatei.c) Wie verschiebe ich danach das Mainprogramm in eine andere Datei (BSp:mymain.c)
Ausgliederung in eine C Datei und dann #include??? War das ernst gemeint???
#include macht nichts anderen als den Inhalt der Datei an der Stelle an der das include steht einzufügen.
Selektieren, Ctrl-X, am Zielplatz Ctrl-V? Oder was meinst du? Abgesehen davon: C-Funktionen gehören nicht in eine Headerdatei.
HildeK schrieb: > Abgesehen davon: C-Funktionen gehören nicht in eine Headerdatei. Wieso? Ich schreibe alle inline-C-Funktionen immer in einer Headerdatei.
Maxim B. schrieb: > Wieso? Ich schreibe alle inline-C-Funktionen immer in einer Headerdatei. Auch wenn es mir einerseits widerstrebt dir zuzustimmen. Hier stimme ich dir aus vollem Herzen zu.
Ich stimme nicht zu. Diese inline-Funktionen müssen static sein. Und dann kann man inline auch weglassen.
static schrieb: > Ich stimme nicht zu. > > Diese inline-Funktionen müssen static sein. Und dann kann man inline > auch weglassen. Es mag mit manchen (alten?) Compilern Probleme geben... Aber in der Regel ist es mittlerweile egal, ob du Funktionen als static oder inline deklarierst. Oder auch beides. Das eine impliziert das andere. Wobei bei inline die ein oder andere Warnung weniger kommt.
Arduino Fanboy D. schrieb: > Aber in der Regel ist es mittlerweile egal, ob du Funktionen als static > oder inline deklarierst. Oder auch beides. > Das eine impliziert das andere. Will man wirklich inline bekommen, reicht manchmal einfache "static inline" nicht. Man muß noch Prototype schreiben, so etwa: static _inline_ void foo(void) __attribute__((_always_inline_)); Macht man das nicht, so wird Compiler wahrscheinlich versuchen, kluger als Programmierer zu werden.
Maxim B. schrieb: > __attribute__((always_inline)); Das steht bei (fast?) allen modernen Kompilern dabei, das ein einfaches inline nur eine Empfehlung ist. Keinesfalls verpflichtend. Und z.B. bei gcc -O0 gar nicht zur Geltung kommt. Zudem kann man bei hohen Optimierungstufen JEDE Funktion als inline annehmen. Es ist also quasi zu einem default Attribut geworden. Der Optimizer entscheidet das anhand seiner Regeln. __attribute__((always_inline)) macht besonders Sinn, wenn man auch bei niedriger Optimierungstufe ein inlinig erzwingen muss/möchte. --- Aber hier, dreht es sich eher um den Sichtbarkeitsbereich, also ob der Linker es zu sehen bekommt. Und da spielt es in gcc C keine Rolle, ob man static oder inline verwendet. Es stören dann nur die Warnings, welche bei inline nicht auftreten.
1 | In file included from c:\temp\arduino_build_848181\sketch\s.c:1: |
2 | c:\temp\arduino_build_848181\sketch\test.h:16:12: warning: 't' defined but not used [-Wunused-function] |
3 | 16 | static int t(int a) |
4 | | ^ |
Um zur Ursprungsfrage zurück zu kommen: Ich würde dafür die Zwischenablage benutzen. Den Block markieren und dann mit Strg-X ausschneiden. Danach an einer anderen Stelle mit Strg-V einfügen. (Generation Smartphone bekommt das nicht mehr mit der Muttermilch)
Arduino Fanboy D. schrieb: > Und z.B. bei gcc -O0 gar nicht zur Geltung kommt Benutzt du diese Einstellung??? Arduino Fanboy D. schrieb: > Der > Optimizer entscheidet das anhand seiner Regeln. Das mag ich nicht, wenn jemand für mich entscheidet. Arduino Fanboy D. schrieb: > __attribute__((always_inline)) macht besonders Sinn, wenn man auch bei > niedriger Optimierungstufe ein inlinig erzwingen muss/möchte Nein, das macht gerade mit Q3 viel Sinn. Sonst macht Compiler wie er mag: mal so mal so. Ich möchte bei bestimmten Funktionen sicher sein, daß ich zu drei oder vier einfachen Befehlen nicht noch eine Menge von push und pop bekomme. Interessant dabei: oft bekommt man mit __attribute__((always_inline)) nicht nur schneller sondern auch kleinere Code. Ein Beispiel: um eine Funktion mit mehreren Argumenten zu rufen, bringt Compiler die zuerst in R24-R25- usw, dann folgt call. Wenn man inline erzwingt, bringt Compiler diese Argumenten gleich in Register, wo ausgeführt wird. Somit ist Leib der Funktion nicht nur wegen fehlenden push und pop kürzer, sondern auch durch nicht mehr notwendigen mov zwischen Registern. So kommt oft vor, daß Gesamtcode auch bei 10x Verwendung mit __attribute__((always_inline)) kürzer ist, als Leib der Funktion + 10x ldi,ldi,ldi,ldi... und call dazu.
Maxim B. schrieb: > Das mag ich nicht, wenn jemand für mich entscheidet. Immerhin ist der Optimierer über Kommandozeilenparameter und pragmas vielfältig konfigurierbar. Maxim B. schrieb: > Benutzt du diese Einstellung??? Selten. z.B. mal kurz wenn ich ein unerklärliches Fehlverhalten vorfinde. Wenn es dann mit -O0 funktioniert, ist die Wahrscheinlichkeit groß, dass ich versehentlich ein UB eingebaut habe. Zudem lässt sich der erzeugte ASM Code leichter lesen, da einen klareren Bezug zum Quellcode hat. In der Regel macht der Optimierer sein Ding recht gut. Klar, gibts auch mal Irritationen, wenn man einen Scheifenzähler Grenzwert erhöht, oder bei einem switch einen Fall hinzufügt. Und der Optimierer darum die Schleifen eben nicht mehr ausrollt, oder das switch/case in eine Sprungtabelle stopfen kann. Aber mit inline hat das alles wenig zu tun. Ansonsten: Takte zählen und Extrawürste backen, nur wenn unbedingt nötig. Meist interessiert mich das Null,Null.
Arduino Fanboy D. schrieb: > Takte zählen und Extrawürste backen, nur wenn unbedingt nötig. Wenn Unterschied schon z.B. 500 Bytes ist, dann muß man manchmal mit dem Kopf denken :)
Maxim B. schrieb: > dann muß man manchmal mit dem > Kopf denken :) Wie gesagt... > Wenn es nötig ist. Ansonsten wird denken auch gerne mal überbewertet.
Ein Beispiel:
1 | static inline void spi_intern_outadr(u8 adr){ |
2 | |
3 | if(adr & (1<<0)){ |
4 | SPI_INTERN_A0_PORT |= (1<<SPI_INTERN_A0); |
5 | }else{ |
6 | SPI_INTERN_A0_PORT &= ~(1<<SPI_INTERN_A0); |
7 | }
|
8 | if(adr & (1<<1)){ |
9 | SPI_INTERN_A1_PORT |= (1<<SPI_INTERN_A1); |
10 | }else{ |
11 | SPI_INTERN_A1_PORT &= ~(1<<SPI_INTERN_A1); |
12 | }
|
13 | if(adr & (1<<2)){ |
14 | SPI_INTERN_A2_PORT |= (1<<SPI_INTERN_A2); |
15 | }else{ |
16 | SPI_INTERN_A2_PORT &= ~(1<<SPI_INTERN_A2); |
17 | }
|
18 | }
|
mit Q3 macht Compiler wie eine gewöhnliche Funktion, mit viel Code, mit bedingten Sprüngen und push-pop. Dabei ist jeder call auch ziemlich groß, 10 Bytes. Erst mit static _inline_ void spi_intern_outadr(u8 adr) __attribute__((_always_inline_)); wird das ordentlich gemacht, mit nur drei cbi oder sbi, je nach der Lage. D.h. 6 Bytes pro Aufruf. Viel schneller und viel kleiner. Unterschied ist zu gravierend, um zu ignorieren.
Kann ich nicht beurteilen, zu sehr aus dem Kontext gerissen. Aber wenn das für dich richtig ist, dann gut, was soll ich sonst dazu sagen? PS: Ich habe mich erinnert, du beziehst dich auf diesen Thread: Beitrag "Lokale Variable statt static, aber optimiert. Wie?" Das dortige Problem würde ich sicherlich gänzlich anders angehen, wenn es sich mir stellen würde... In der Arduino Welt haben wir dafür: https://www.arduino.cc/en/Reference/SPISettings Ob das jetzt effektiver ist? Vermutlich nicht wirklich. Aber ein Programm, welches das nutzt ist schnell zusammen gedengelt und auch µC Familien übergreifend nutzbar.
Arduino Fanboy D. schrieb: > Wenn es dann mit -O0 funktioniert, ist die Wahrscheinlichkeit groß, dass > ich versehentlich ein UB eingebaut habe. Ja. Ist mir zum Glück noch nie passiert. Ich schau mir allerdings auch die Warnungen des Compilers und der IDE an.
Arduino Fanboy D. schrieb: > Aber in der Regel ist es mittlerweile egal, ob du Funktionen als static > oder inline deklarierst. Oder auch beides. > Das eine impliziert das andere. Was genau bedeutet denn eine Inline-Funktion?
RBK schrieb: > Arduino Fanboy D. schrieb: >> Aber in der Regel ist es mittlerweile egal, ob du Funktionen als static >> oder inline deklarierst. Oder auch beides. >> Das eine impliziert das andere. > > Was genau bedeutet denn eine Inline-Funktion? ???? Was ich weiß, sachte ich schon! Arduino Fanboy D. schrieb: > Das steht bei (fast?) allen modernen Kompilern dabei, das ein einfaches > inline nur eine Empfehlung ist. > Keinesfalls verpflichtend. > Und z.B. bei gcc -O0 gar nicht zur Geltung kommt. Früher war alles besser! Sogar die Zukunft, und das inline Attribut hatte damals noch eine garantierte Wirkung. --------- Nachtrag (nach etwas überlegen): > Was genau bedeutet denn eine Inline-Funktion? Eine inline Funktion ist einen inline Funktion, wenn der Kompiler sie inline eingebunden hat. Was recht logisch und zwangsläufig zur Folge hat, dass der Linker sie nicht auflösen muss, wenn man sie als solche deklariert hat.
Stefan ⛄ F. schrieb: > Ja. Ist mir zum Glück noch nie passiert. Ich schau mir allerdings auch > die Warnungen des Compilers und der IDE an. Naja.. Der Compiler meldet nicht alles, was in einen UB führt.
RBK schrieb: > Was genau bedeutet denn eine Inline-Funktion? So etwa wie Macros, nur anders geschrieben.
Maxim B. schrieb: > So etwa wie Macros, nur anders geschrieben. Genau https://de.wikipedia.org/wiki/Makro
Arduino Fanboy D. schrieb: > Eine inline Funktion ist einen inline Funktion, wenn der Kompiler sie > inline eingebunden hat. Was recht logisch und zwangsläufig zur Folge > hat, dass der Linker sie nicht auflösen muss, wenn man sie als solche > deklariert hat. Das stimmt zwar, ist aber nur ein Nebeneffekt, der sich aus der Logik der Sache ergibt. Was inline wirklich tut (wenn es das tut, was man erwarten könnte), ist: Verzichte auf den Callframe! Und bei "Hochsprachen" (C/C++ sein hier mal mitgerechnet) ggf. auch noch: Und auf weiteres sinnloses Gewichse, was nur aus den intelligenzmäßig etwas unterbelichteten Makro-Bausteinen resultiert, die einen C/C++-Compiler im Kern ausmachen... Im Endeffekt wird also der der Nutzcode der inline-Funktion direkt in der Funktion generiert, die diese Inline-Funktion aufruft. Von diesem Nutzcode gibt es also für jede aufrufende Code-Instanz eine eigene Inkarnation im Programmspeicher. Das ist (fast) immer schlecht für eine Optimierung auf minimale Codegröße, aber im Gegenzug oft sehr gut für eine Optimierung auf Geschwindigkeit. Das Grundprinzip ist simpel. Verdammenswürdig ist nur, dass der Compiler sich erfrecht, die letzte Entscheidung selber treffen zu wollen. Das steht ihm nicht zu, er ist nur ein Werkzeug. Da könnte ja auch eine Kombizange auf die Idee kommen, zu entscheiden, nö, heute ist Montag, da mag ich keine Drähte trennen, heute sind nur Flachzangen-Anwendungen drin. Kein Handwerker mit Berufsehre würde so eine Kombizange ernsthaft benutzen wollen, das Ding landet natürlich sofort im Müll. C-Programmierer sind da wohl härter im Nehmen. Die lassen sich von ihrem Werkzeug vorschreiben, was besser ist. Auch dann, wenn es nicht wirklich besser ist...
c-hater schrieb: > C-Programmierer sind da wohl härter im Nehmen. Ist es nicht eher so, dass gerade C "trust the programmer" als Logo hat? Die anderen Programmiersprachen trauen dem Programmierer doch nicht mal zu Speicher zu reversieren / freigeben.
c-hater schrieb: > Kein Handwerker mit Berufsehre würde so eine so eine Sprache benutzen wie du. Ich mag dir gar nicht die Hand geben, wer weiß wo die gerade war.
Stefan ⛄ F. schrieb: > so eine Sprache benutzen wie du. Welche Passge hat dir denn nicht gefallen? Ich kann da nix verwerfliches finden? Hach, verdammt. Ersetze meinetwegen "Gewichse" durch "Gerödel" oder was immer du für sinnlosen, nutzlosen, zeitfressenden Code als angemessenen Bezeichnung wählen würdest. An den Fakten ändert das exakt garnix!
c-hater schrieb: > ich kann da nix verwerfliches finden? Das war mir schon klar. Denn in beinahe jedem Beitrag beleidigst du in einem großen Rundumschlag Gott und die Welt die sich um dich dreht. > An den Fakten ändert das exakt garnix! Das sind keine Fakten, sondern deine seltsamen Meinungen. Du kommst mir wie der Geisterfahrer vor, der sich darüber wundert, dass alle anderen falsch herum fahren.
Stefan ⛄ F. schrieb: >> An den Fakten ändert das exakt garnix! > > Das sind keine Fakten Doch, das sind Fakten. Jeder Compilerbauer wird dir das bestätigen können. Er wird dir vermutlich nur eins nicht bestätigen wollen, dass es nicht gut ist, die letzte Entscheidung bezüglich des Inlining dem Compiler vorzubehalten... Auch das ergibt sich aus dem beobachteten Sachverhalt. Jedenfalls für jeden, der logisch denken kann...
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.