funktionen inlinen

Gast #2964518
Lesenswert?

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!
Moderator Persönliche Seite #2964538
Lesenswert?

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)
Persönliche Seite #2964558
Lesenswert?

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.
Gast #2964596
Lesenswert?

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.
#2964743
Lesenswert?

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.
Persönliche Seite #2964751
Lesenswert?

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?
#2964769
Lesenswert?

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?
#2964777
Lesenswert?

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.
#2964783
Lesenswert?

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
#2964862
Lesenswert?

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.
Gast #2964870
Lesenswert?

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").
#2964922
Lesenswert?

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

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