static inline in Projektorganisation

#4254786
Lesenswert?

Hallo zusammen,
mich interessiert, wie ihr eure Projekte organisiert, und um genau zu 
sein: Wie ihr "static inline"-Funktionen organisiert.

David Kieras empfiehlt in den "C Header File Guidelines" (siehe hier:
http://www.umich.edu/~eecs381/handouts/CHeaderFileGuidelines.pdf )
niemals Funktionen in *.h-Dateien zu tun, sondern in *.inc-Dateien.

IDEs wie Visual Studio oder Eclipse *) kennen diese Endung allerdings 
nicht, was dann dazu führt, daß ihr Komfort deutlich gemindert wird, 
weil Funktionen wie "bei Fehlermeldung direkt in die richtige Zeile 
springen" oder Refaktoring/Umbenennen fehlen.


Desweiteren kann man entweder das berühmte:
1
static inline __attribute__((always_inline))
vor jede Funktion schreiben, was der Lesbarkeit nicht wahnsinnig dient, 
oder in jede Datei mit solchen Funktionen einen Header einbinden, der 
ein Kurzsymbol definiert.

Deswegen: Wie organisiert ihr static inline-Funktionen in einem Projekt?

Viele Grüße
W.T.

*) hier läßt es sich allerdings mit wenigen Handgriffen nachrüsten
#4254817
Lesenswert?

Wenn dir alle anderen Regeln bekannt (und begründet) vorkommen, dann ist 
diese letzte ehe ein formales Problem. Ist diese "always inline" 
Funktion Definition oder Implementierung?
Formal beides, pragmatisch (bei mir) nur ersteres, wenn aber überhaupt, 
dann würde ich ".inl" vorziehen. ".inc" ist eher das 
Assembler-Äquivalent zum ".h".
Moderator Persönliche Seite #4254877
Lesenswert?

Walter T. schrieb:
> sondern in *.inc-Dateien.

Nein, das bezieht er ausdrücklich nur auf C-Code, der aus irgendeinem
Grund in anderen C-Code direkt importiert werden soll.  Sowas kann
einem beispielsweise dienlich sein, wenn man den Inhalt eines
statischen Arrays extern durch ein Tool generieren lassen will:
1
static uint8_t lookup_table[LOOKUP_TABLE_SIZE] = {
2
#  include "lookuptable.inc"
3
};

lookuptable.inc wird dabei durch einen Perl- oder Pythonscript oder
etwas ähnliches (über die Build-Infrastruktur, also Makefile oder
Scons oder was auch immer) generiert.  In diesem Falle sollte man
das aber nicht "lookuptable.c" nennen, da es eben keine eigenständig
compilierbare Datei ist.

Über inline-Funktionen hat er sich nicht ausgelassen in seinem
Schriebs.  Ich würde sie, obwohl sie bei ihrer Anwendung in der Tat
Code generieren, dennoch im normalen Headerfile lassen.  Alles andere
ist meiner Meinung nach widersinnig.

Exkursion in C++: es käme doch auch keiner auf die Idee, in einer
Klasse inline implementierte Methoden in separate Dateien auszulagern:
1
class foo {
2
  private:
3
    int percent;
4

5
  public:
6
    foo(void);
7

8
    int get_percent { return percent; }
9
    void set_percent(int nval) {
10
      if (nval >= 0 && nval <= 100)
11
        percent = nval;
12
    }
13
};

Die typischen “getter”- und “setter”-Methoden (get_percent(),
set_percent() in diesem Falle) werden sehr oft in dieser Form als
inline-Implementierungen realisiert.
(Firma: Torrox.de) #4254996
Lesenswert?

Jörg W. schrieb:

> Exkursion in C++: es käme doch auch keiner auf die Idee, in einer
> Klasse inline implementierte Methoden in separate Dateien auszulagern:

Doch, dass kann Sinn machen, wenn Du das template nur für eine 
überschaubare Menge von Parameters benötigst. Dann kannst Du die in 
einer separaten Übersetzungseinheit explizit instanziieren und nur dort 
brauchst Du dann die Funktionsdefinitionen.

@Walter: Vielleicht wäre ein C++ compiler auch eine Lösung für Dich? 
Dort kannst Du Funktionen als `inline` deklarieren:
1
void inline foo()
2
{
3
...
4
}
Gast #4255024
Lesenswert?

Walter T. schrieb:
> IDEs wie Visual Studio oder Eclipse *) kennen diese Endung allerdings
> nicht,

Manchmal muss man sich den Realitäten beugen. Dazu gehört auch, dass man 
sich nicht-standard Konfigurationen von IDEs gut überlegen sollte. Wenn 
man sich den Realitäten beugt, dann bleibt .c oder .h.

.h bietet sich eher an. Bei ganz großen Projekten mit vielen 
Inline-Funktionen kann man eine Konvention einführen, dass man normale 
Header und Inline-Header nochmal trennt. Entweder durch ein 
Unterverzeichnis
1
#include "api.h"          // Ein bestimmtes API
2
#include "inline/api.h"   // Die Inline-Funktionen des API

oder eine Namenskonvention:
1
#include "api.h"          // Ein bestimmtes API
2
#include "api.in.h"       // Die Inline-Funktionen des API

Beides aber wirklich nur wenn Inline-Funktionen überhand nehmen und man 
sonst den Durchblick verliert. Ansonsten
1
#include "api.h"          // API mit Inline-Funktionen

> Desweiteren kann man entweder das berühmte:static inline
> __attribute__((always_inline))
> vor jede Funktion schreiben, was der Lesbarkeit nicht wahnsinnig dient,
> oder in jede Datei mit solchen Funktionen einen Header einbinden, der
> ein Kurzsymbol definiert.

Das hängt vom Aufdensackgehfaktor ab. Irgendwann ist der >= 10, dann 
gibt es ein #define INLINE ... oder ähnliches.
#4255089
Lesenswert?

Danke für die Antworten.

Jörg W. schrieb:
> Ich wäre übrigens mit __attribute__((always_inline)) vorsichtig.

Danke, das bin ich :-).

Mein Code ist ein wenig gespickt mit dem Aufruf von Funktionen wie:
1
    /* Einzelnes oder mehrere Bits eines Ports setzen
2
     *
3
     * GPIOx
4
     * Pin: Bitmaske */
5
    static inline __attribute__((always_inline)) void
6
    io_SetBit(GPIO_TypeDef * const pPORTx, const uint8_t Pin) 
7
    {
8
        *pPORTx |= Pin;
9
    }
die in jedem Bitbanging-Treiber zigfach aufgerufen werden. Sobald es 
eine einzelne Stelle gibt, wo die Funktion mit einer Variablen anstelle 
einer Konstanten aufgerufen wird, macht mir die Optimierung -S einen 
Strich durch die Rechnung und auch an allen anderen Stellen keinen 
einfachen SBI/CBI mehr. Diese und ähnliche Funktionen sind allerdings 
auch die einzigen "static inline" im ganzen Projekt.

Ich hatte die Aufteilung in .c und .h-Dateien auch immer als Trennung 
von Schnittstelle und Implementierung verstanden. Nach dieser Logik 
hätten "static inline"-Funktionen eindeutig ihren Platz in der .c-Datei 
(was eben nur technisch nicht geht). So hatte ich auch den Vorschlag mit 
den .inc-Dateien gelesen.

Aber eure Vorgehensweise ergibt natürlich auch einen Sinn: Man muß 
nichts verbiegen, ärgert sich nicht über fehlende Unterstützung in der 
Programmierumgebung und es funktioniert einfach.

Ich werde das also wieder zurückändern.

Viele Grüße
W.T.
Moderator Persönliche Seite #4255104
Lesenswert?

Walter T. schrieb:

> mich interessiert, wie ihr eure Projekte organisiert, und um genau zu
> sein: Wie ihr "static inline"-Funktionen organisiert.

Siehe auch:

  Beitrag ""Include-Libs" - Teufelswerk?"

ICh persönlich mache da gar nichts mehr in dieser Richtung. static 
reicht. Dann kann der Compiler entscheiden, ob er diese inlined oder 
nicht. Das kann er selbst meist besser.

> David Kieras empfiehlt in den "C Header File Guidelines" (siehe hier:
> http://www.umich.edu/~eecs381/handouts/CHeaderFileGuidelines.pdf )
> niemals Funktionen in *.h-Dateien zu tun, sondern in *.inc-Dateien.

Nimm -Os -flto sowohl als Compiler- als auch als Linkerflag. Dann kann 
der gcc sogar modulübergreifende Funktionsaufrufe "inlinen", wenn er das 
für sinnvoll hält.

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