it-swarm.com.de

extern inline

Ich verstehe, dass "Inline" an sich ein Vorschlag an den Compiler ist, und nach seinem Ermessen kann er die Funktion inline einfügen oder nicht, und es wird auch verknüpfbarer Objektcode erzeugt.

Ich denke, dass "statische Inline" dasselbe tut (kann oder darf nicht Inline), aber bei Inline keinen verknüpfbaren Objektcode erzeugen (da kein anderes Modul eine Verknüpfung herstellen kann).

Wo passt "extern inline" ins Bild?

Angenommen, ich möchte ein Präprozessor-Makro durch eine Inline-Funktion ersetzen und fordern, dass diese Funktion eingebettet wird (z. B. weil sie die __FILE__- und __LINE__-Makros verwendet, die für den Aufrufer aufgelöst werden sollen, aber nicht die aufgerufene Funktion). Das heißt, ich möchte einen Compiler- oder Linker-Fehler sehen, falls die Funktion nicht eingebettet wird. Führt dies "extern inline"? (Ich gehe davon aus, dass dies nicht möglich ist, wenn dies nicht der Fall ist, wenn Sie sich nicht an ein Makro halten.)

Gibt es Unterschiede zwischen C++ und C?

Gibt es Unterschiede zwischen verschiedenen Compiler-Herstellern und -Versionen?

83
wilbur_m

in K & R C oder C89 war Inline nicht Teil der Sprache. Viele Compiler implementierten es als Erweiterung, aber es gab keine definierte Semantik für die Funktionsweise. GCC war einer der ersten, der Inlining implementierte, und führte die Konstrukte inline, static inline und extern inline ein. Die meisten Compiler vor C99 folgen im Allgemeinen ihrem Beispiel. 

GNU89:

  • inline: Die Funktion kann eingebettet sein (es ist jedoch nur ein Hinweis). Eine Out-of-Line-Version wird immer ausgegeben und ist von außen sichtbar. Daher können Sie nur eine solche Inline in einer Compilationseinheit definieren, und jeder andere muss es als Out-of-Line-Funktion sehen (oder Sie erhalten zur Linkzeit doppelte Symbole).
  • extern inline generiert keine Out-of-Line-Version, ruft jedoch möglicherweise eine auf (die Sie daher in einer anderen Kompilierungseinheit definieren müssen). Die One-Definitions-Regel gilt jedoch; Die Inline wird hier angeboten, falls der Compiler dies stattdessen aufruft.
  • static inline generiert keine extern sichtbare Out-of-Line-Version, obwohl möglicherweise eine statische Datei generiert wird. Die Ein-Definition-Regel gilt nicht, da weder ein externes Symbol ausgegeben wird, noch ein Aufruf an ein Symbol erfolgt.

C99 (oder GNU99):

  • inline: wie GNU89 "extern inline"; Es wird keine von außen sichtbare Funktion ausgegeben, es kann jedoch eine aufgerufen werden, die existieren muss
  • extern inline: wie GNU89 "Inline": Es wird ein extern sichtbarer Code ausgegeben, so dass höchstens eine Übersetzungseinheit diesen verwenden kann.
  • static inline: wie GNU89 "statische Inline". Dies ist die einzige tragbare zwischen gnu89 und c99

C++:

Eine Funktion, die überall Inline ist, muss überall Inline sein und dieselbe Definition haben. Der Compiler/Linker sortiert mehrere Instanzen des Symbols aus. Es gibt keine Definition von static inline oder extern inline, obwohl viele Compiler sie haben (normalerweise nach dem gnu89-Modell).

119
puetzk

Ich glaube, Sie missverstehen __FILE__ und __LINE__ basierend auf dieser Aussage:

weil es __FILE__ und .__ verwendet. __LINE__-Makros, die für den Anrufer aufgelöst werden sollen, jedoch nicht die Funktion

Es gibt mehrere Phasen der Kompilierung, und die Vorverarbeitung ist die erste. __FILE__ und __LINE__ werden in dieser Phase ersetzt. Zu dem Zeitpunkt, zu dem der Compiler die Funktion für das Inlining berücksichtigen kann, wurde sie bereits ersetzt. 

29
Don Neufeld

Es hört sich an, als würden Sie versuchen, so etwas zu schreiben:

inline void printLocation()
{
  cout <<"You're at " __FILE__ ", line number" __LINE__;
}

{
...
  printLocation();
...
  printLocation();
...
  printLocation();

und hoffen, dass Sie jedes Mal andere Werte drucken. Wie Don sagt, werden Sie nicht, weil __FILE__ und __LINE__ vom Präprozessor implementiert werden, Inline jedoch vom Compiler. Wenn Sie also printLocation aufrufen, erhalten Sie dasselbe Ergebnis.

Die Methode nur, mit der Sie dies erreichen können, besteht darin, printLocation zu einem Makro zu machen. (Ja, ich weiß...)

#define PRINT_LOCATION  {cout <<"You're at " __FILE__ ", line number" __LINE__}

...
  PRINT_LOCATION;
...
  PRINT_LOCATION;
...
12
Roddy

Die Situation mit Inline, Static Inline und Extern Inline ist kompliziert, nicht zuletzt weil gcc und C99 leicht unterschiedliche Bedeutungen für ihr Verhalten definieren (und vermutlich auch C++). Sie finden nützliche und detaillierte Informationen zu den Funktionen in C hier .

3
Simon Howard

Makros sind hier Ihre Wahl und nicht die Inline-Funktionen. Eine seltene Gelegenheit, in der Makros Inline-Funktionen beherrschen. Versuchen Sie folgendes: Ich habe diesen "MACRO MAGIC" Code geschrieben und er sollte funktionieren! Getestet auf gcc/g ++ Ubuntu 10.04

//(c) 2012 enthusiasticgeek (LOGGING example for StackOverflow)

#ifdef __cplusplus

#include <cstdio>
#include <cstring>

#else

#include <stdio.h>
#include <string.h>

#endif

//=========== MACRO MAGIC BEGINS ============

//Trim full file path
#define __SFILE__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/')+1 : __FILE__ )

#define STRINGIFY_N(x) #x
#define TOSTRING_N(x) STRINGIFY_N(x)
#define _LINE (TOSTRING_N(__LINE__))

#define LOG(x, s...) printf("(%s:%s:%s)"  x "\n" , __SFILE__, __func__, _LINE, ## s);

//=========== MACRO MAGIC ENDS ============

int main (int argc, char** argv) {

  LOG("Greetings StackOverflow! - from enthusiasticgeek\n");

  return 0;
}

Definieren Sie diese Makros für mehrere Dateien in einer separaten Header-Datei, einschließlich derselben in jeder c/cc/cxx/cpp-Datei. Bitte ziehen Sie Inline-Funktionen oder Konstantenbezeichnungen (je nach Fall) Makros vor, wo immer dies möglich ist.

2

Anstatt zu antworten "Was macht es?", Antworte ich "Wie kann ich es tun lassen, was ich will?" Es gibt 5 Inlinearten, die alle in GNU C89, Standard C99 und C++ verfügbar sind:

immer inline, sofern nicht die adresse verwendet wird

Fügen Sie __attribute__((always_inline)) zu einer beliebigen Deklaration hinzu, und verwenden Sie dann einen der untenstehenden Fälle .__, um die Möglichkeit zu berücksichtigen, dass dessen Adresse verwendet wird.

Sie sollten dies wahrscheinlich niemals verwenden, es sei denn, Sie benötigen eine Semantik (z. B. um die Assembly in einer bestimmten Weise zu beeinflussen oder alloca zu verwenden). Der Compiler weiß normalerweise besser als Sie, ob es sich lohnt.

inline und emittiere ein schwaches Symbol (wie C++ oder "mach es einfach")

__attribute__((weak))
void foo(void);
inline void foo(void) { ... }

Beachten Sie, dass hierdurch eine Reihe von Kopien desselben Codes liegen gelassen wird und der Linker eine willkürlich auswählt.

inline, aber kein Symbol ausgeben (externe Referenzen lassen)

__attribute__((gnu_inline))
extern inline void foo(void) { ... }

emittiere immer (für eine TU, um das Vorhergehende aufzulösen)

Die angedeutete Version gibt in C++ ein schwaches Symbol aus, aber in beiden Dialekten von C ein starkes Symbol:

void foo(void);
inline void foo(void) { ... }

Oder Sie können es ohne den Hinweis tun, der in beiden Sprachen ein starkes Symbol ausstrahlt:

void foo(void) { ... }

Im Allgemeinen wissen Sie, welche Sprache Ihre TU ist, wenn Sie die Definitionen bereitstellen, und benötigen wahrscheinlich nicht viel Inlining.

inline und Emit in jeder TU

static inline void foo(void) { ... }

Für alle diese Optionen außer der Variablen static können Sie oben eine void foo(void)-Deklaration hinzufügen. Dies hilft bei der "bewährten Methode", saubere Header zu schreiben und dann eine separate Datei mit den Inline-Definitionen zu #includeen. Wenn Sie Inline im C-Stil verwenden, #define einige Makros in einem dedizierten TU anders, um die Out-of-Line-Definitionen bereitzustellen.

Vergessen Sie extern "C" nicht, wenn der Header von C und C++ verwendet werden kann!

0
o11c