hi, ich muss innerhalb einer c-Datei öfter mal einen bestimmten Ausgang setzen oder löschen. (immer der gleiche, PORTA Pin3) Ich will nur nicht an mehreren Stellen den Registerzugriff haben und Bits herumschieben, deswegen würde ich gerne eine kleine Funktion dafür verwenden. void setOutput(bool value) { if (value == TRUE) PORTA |= (1 << 3); else PORTA &= ~(1 << 3); } eigentlich ist doch ein Funktionsaufruf overkill für so eine simple Aufgabe. aber der Compiler kann doch das inlinen oder? und die if-abfrage kann er ja auch rausschmeissen? so dass letztendlich nur dasteht: PORTA |= (1 << 3); Macht er das immer? Oder sollte ich static inline dazuschreiben? ich versteh den assembler code leider nicht drum kann ich nicht nachschaun was der Compiler draus macht :-( danke schon mal!
moop schrieb: > eigentlich ist doch ein Funktionsaufruf overkill für so eine simple > Aufgabe. Ja. > aber der Compiler kann doch das inlinen oder? Unter bestimmten Voraussetzungen: Ja. Zum Beispiel wäre es vorteilhaft, die Funktion static zu definieren. Dann weiß der Compiler, dass sie ausschließlich aus diesem C-Modul aufgerufen wird. > und die if-abfrage kann er ja auch rausschmeissen? Kommt drauf an: Wenn Du die Funktion mit einem konstanten Wert aufrufst, ja. Wenn Du sie aber mit einer Variablen aufrufst, die erst at runtime einen Wert erhält, kann der Compiler das nicht. > Macht er das immer? Oder sollte ich static inline dazuschreiben? Standardmässig sollte er so eine kleine Funktion inlinen. Wenn Du sie noch static machst, sollte das reichen. Eine Alternative wäre der Einsatz des Preprocessors:
1 | #define SET_OUTPUT_HIGH PORTA |= (1 << 3)
|
2 | #define SET_OUTPUT_LOW PORTA &= ~(1 << 3)
|
Du kannst es so verwenden:
1 | #include <stdbool.h> |
2 | #include <avr/io.h> |
3 | |
4 | static __inline__ __attribute__((always_inline)) |
5 | void setOutput (const bool value) |
6 | {
|
7 | if (value) |
8 | PORTA |= (1 << 3); |
9 | else
|
10 | PORTA &= ~(1 << 3); |
11 | }
|
__inline__ anstatt inline geht auch mit C90; wenn du C99 verwendest geht auch inline. Das always_inline inlint auch ohne Optimierung, und in dem Fall wird das const gebraucht um den Vergleich rauszuwerfen. Explizit genen true zu vergleichen ist übel, weil alles != false als true genommen wird. Bevorzugt steht so eine Funktion in einem Header.
hi und danke euch! wenn ich die funktion aber nur in einer Datei benutze dann passt sie aber auch in die c-Datei anstatt in den header, richtig?
Welches Problem versuchst du ueberhaupt zu loesen? Wenn es kein Problem ist, dann loese es auch nicht.
Ich hab mir dazu einen Header geschrieben, der alle Pins als Bitvariablen definiert. Damit geht es ganz einfach und lesbar:
1 | #include "sbit.h" |
2 | |
3 | #define LED0 PORT_A3
|
4 | #define LED0_oe DDR_A3
|
5 | |
6 | LED0_oe = 1; // output |
7 | LED0 = 0; // low |
8 | LED0 = 1; // high |
Peter
wie in meinem ersten Post geschrieben: ein Pin-Setzen oder -Löschen zentral an einer Stelle zu machen anstatt den Portzugriff und das Geshifte an mehreren Stellen im Code zu haben. Aber möglichst so, das der resultierende Code genauso performant ist. Und nebenbei noch was über den Compiler zu lernen.
moop schrieb: > das der resultierende Code genauso performant ist. Ob ausgeschrieben, Inline oder Macro, der Code ist immer gleich groß. Der Compiler ersetzt das konstante Shift durch SBI/CBI. Compiler sind recht gut im Ausrechnen konstanter Ausdrücke. Sie rechnen lieber gleich, anstatt Laufzeitcode zu erzeugen. Peter
Johann L. schrieb: > Das always_inline inlint auch ohne Optimierung, und in dem Fall wird das > const gebraucht um den Vergleich rauszuwerfen. Unnötig. Wenn das als normale Funktion aufgerufen wird, muss dort verglichen werden ob du nun const schreibst oder nicht. Wenn es inline expandiert wird, erkennt der Compiler, dass der Wert von value einen bekannten Wert hat und optimiert den Vergleich weg, const oder nicht.
Andreas B. schrieb: > Johann L. schrieb: >> Das always_inline inlint auch ohne Optimierung, und in dem Fall wird das >> const gebraucht um den Vergleich rauszuwerfen. > > Unnötig. Wenn das als normale Funktion aufgerufen wird, muss dort > verglichen werden ob du nun const schreibst oder nicht. Wenn es inline > expandiert wird, erkennt der Compiler, dass der Wert von value einen > bekannten Wert hat und optimiert den Vergleich weg, const oder nicht. Bitte überprüfe deine Behauptung! (Hab ich zB gemacht, bevor ich meinen Beitrag verfasst hab). Du behauptest also, daß mit -O0 der gleiche Code erzeugt wird, egal ob da ein const steht oder nicht?
Johann L. schrieb: > Du behauptest also, daß mit -O0 der gleiche Code erzeugt wird Immer diese praxisfernen Annahmen. Default ist -Os und das aus gutem Grund. Wer -O0 benutzt, dem kommts auch nicht mehr auf die paar Byte mehr an, dem sind 500% Overhead egal. Peter
Macht es bei -Os eigentlich einen Unterschied ob man eine static-Funktion mit "inline" kennzeichnet oder nicht? Theoretisch sollte durch -Os ja immer die Variante mit kleinstmöglichem Code erzeugt werden? Oder werden explizit gekennzeichnete Inline-Funktionen (also nur mit "inline", nicht "always_inline") auch geinlint, wenn der Code dadurch ein paar Bytes größer, aber dafür schneller wird?
Peter Dannegger schrieb: > Johann L. schrieb: >> Du behauptest also, daß mit -O0 der gleiche Code erzeugt wird > > Immer diese praxisfernen Annahmen. > Default ist -Os und das aus gutem Grund. In GCC ist -O0 der Default. Aber darum geht es hier garnicht. Sondern darum, daß unüberlegt und grundlos offenbar falsche Aussagen bemacht werden.
Johann L. schrieb: > In GCC ist -O0 der Default. Aber darum geht es hier garnicht. Sondern > darum, daß unüberlegt und grundlos offenbar falsche Aussagen bemacht > werden. Ja. ok. Momentan ist das beim gcc eben so. Allerdings erschliesst sich mir aus Sicht des Sprachstandards nicht, warum das so sein sollte. Das irgendmal wer entschieden hat, diese Optimierung in -O0 nur bei explizit const markierten Argumenten zu machen, ist zwar ein Faktum. Nur sehe ich ehrlich gesagt keinen Grund, warum das so sein muss. > -O0 Na ja. Der sinnvolle Default in der AVR-Programmierung ist nun mal -Os und nicht -O0. Von daher dürften wohl die wenigsten jemals -O0 benutzen. Von daher: sei ein wenig nachsichtig, wenn wir nicht für alle Optimierungen auswendig wissen, welche Optimierung unter welchen Nebenbedingung durchgeführt wird und wann nicht. Manche Optimierungen sind so trivial, dass man wohl davon ausgeht, dass der Compiler sie praktisch immer machen wird.
Fabian O. schrieb: > Theoretisch sollte durch -Os ja immer die Variante mit kleinstmöglichem > Code erzeugt werden? Grau ist alle Theorie. Fabian O. schrieb: > Oder werden explizit gekennzeichnete > Inline-Funktionen (also nur mit "inline", nicht "always_inline") auch > geinlint Nicht nur die, sondern auch alle, die der Compiler als kurz einschätzt (ohne daß sie es wirklich sind). Daher sollte man das ungefragte Inlinen explizit verbieten, was nochmal drastisch kleineren Code ergibt:
1 | -fno-inline-small-functions |
Peter
Das hatten wir schon mal, ich bin da anderer Meinung. ;-) Ich möchte genau dieses Inlinen von "kleinen" Funktionen gerne haben, denn ich gliedere meinen Code gerne in kurze Unterfunktionen, um bestimmten Aktionen Namen zu geben, selbst wenn sie zum Teil nur aus einer Anweisung bestehen oder nur von einer Stelle aus aufgerufen werden. Solche Dinge wie Hardwarekonfiguration und Registerzugriffe wären ein Paradebeispiel. Wenn man sie als "static inline"-Funktion in ein Headerfile auslagert, erhält man schön lesbaren und hardwareunabhängigen Code. Dafür möchte ich aber nicht mit langsameren Code bestraft werden. Wenn inline-Funktionen als auch geinlint werden, obwohl es mit einem echten Funktionsaufruf noch etwas kleiner ginge, fände ich daher nicht schlimm. Ich bin aber auch einverstanden, wenn der GCC -Os als "so klein wie nur irgendwie geht, Geschwindigkeit und Stacknutzung völlig egal" interpretiert. Mich würde nur interessieren, wie es tatsächlich ist.
Benutzt man -fno-inline-small-functions nicht eher deswegen weil der Compiler nicht weiß ob die Funktion 2, 10 oder 1000 mal geinlined werden muss? Ich denke den Code einer Funktion kann er recht gut abschätzen, er erzeugt ihn ja (Vorrausgesetzt, du und der Compiler (bzw. dessen Programmierer) habt die selbe Definition von "klein").
Fabian O. schrieb: > Mich würde nur interessieren, wie es tatsächlich ist. Ganz einfach: 1. -fno-inline-small-functions -> kein heimliches inline 2. static inline -> meistens inline (ich hatte schonmal den Fall, wo es ignoriert wurde) 3. _attribute_ ((always_inline)) -> immer inline 4. globale Optimierung über alle Sourcen: -> alle nur einmal aufgerufenen Funktionen inline 5. _attribute_ ((noinline)) -> niemals inline Die Zahlen 1..5 geben die Rangfolge an (5 = höchste). Peter
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.