Angenommen, ich habe diese kleine Funktion in einer Quelldatei
static void foo() {}
und ich baue eine optimierte Version meiner Binärdatei, aber ich möchte nicht, dass diese Funktion inline ist (aus Optimierungsgründen). Gibt es ein Makro, das ich in einen Quellcode einfügen kann, um das Inlining zu verhindern?
Du willst die gcc
-Spezifisch noinline
Attribut.
Dieses Funktionsattribut verhindert, dass eine Funktion für das Inlining berücksichtigt wird. Wenn die Funktion keine Seiteneffekte hat, gibt es andere Optimierungen als Inlining, die dazu führen, dass Funktionsaufrufe wegoptimiert werden, obwohl der Funktionsaufruf live ist. Um zu verhindern, dass solche Aufrufe wegoptimiert werden, put
asm ("");
Verwenden Sie es wie folgt:
void __attribute__ ((noinline)) foo()
{
...
}
GCC hat einen Schalter namens
-fno-inline-small-functions
Verwenden Sie das also, wenn Sie gcc aufrufen. Aber der Nebeneffekt ist, dass alle anderen kleinen Funktionen auch nicht inliniert sind.
Ich weiß, dass sich die Frage auf GCC bezieht, aber ich dachte, es könnte nützlich sein, auch einige Informationen über Compiler und andere Compiler zu haben.
GCCs
noinline
Das Funktionsattribut ist auch bei anderen Compilern ziemlich beliebt. Es wird mindestens unterstützt von:
- Clang (überprüfen Sie mit
__has_attribute(noinline)
)
- Intel C/C++ Compiler (ihre Dokumentation ist schrecklich, aber ich bin mir sicher, dass sie auf 16.0+ funktioniert)
- Oracle Solaris Studio zurück auf mindestens 12.2
- ARM C/C++ Compiler zurück auf mindestens 4.1
- IBM XL C/C++ zurück auf mindestens 10.1
- TI 8.0+ (oder 7.3+ mit –gcc, das definiert
__TI_GNU_ATTRIBUTE_SUPPORT__
)
Darüber hinaus unterstützt MSVC
__declspec(noinline)
zurück zu Visual Studio 7.1. Intel unterstützt es wahrscheinlich auch (sie versuchen, sowohl mit GCC als auch mit MSVC kompatibel zu sein), aber ich habe mich nicht darum gekümmert, das zu überprüfen. Die Syntax ist im Grunde dieselbe:
__declspec(noinline)
static void foo(void) { }
PGI 10.2+ (und wahrscheinlich älter) unterstützt a noinline
Pragma, das für die nächste Funktion gilt:
#pragma noinline
static void foo(void) { }
TI 6.0+ unterstützt a
FUNC_CANNOT_INLINE
Pragma, das (ärgerlicherweise) in C und C++ unterschiedlich funktioniert. In C++ ist es ähnlich wie bei PGI:
#pragma FUNC_CANNOT_INLINE;
static void foo(void) { }
In C wird jedoch der Funktionsname benötigt:
#pragma FUNC_CANNOT_INLINE(foo);
static void foo(void) { }
Cray 6.4+ (und möglicherweise früher) verfolgt einen ähnlichen Ansatz und erfordert den Funktionsnamen:
#pragma _CRI inline_never foo
static void foo(void) { }
Oracle Developer Studio unterstützt auch ein Pragma, das den Funktionsnamen nimmt und zurückgeht auf mindestens Forte Developer 6aber beachten Sie, dass es kommen muss nach die Erklärung, auch in neueren Versionen:
static void foo(void);
#pragma no_inline(foo)
Je nachdem, wie engagiert Sie sind, könnten Sie ein Makro erstellen, das überall funktioniert, aber Sie müssten den Funktionsnamen sowie die Deklaration als Argumente haben.
Wenn Sie, OTOH, mit etwas einverstanden sind, das für die meisten Menschen funktioniert, können Sie mit etwas davonkommen, das ein wenig ästhetisch ansprechender ist und keine Wiederholung erfordert. Das ist der Ansatz, den ich gewählt habe Hedleywo die aktuelle Version von
HEDLEY_NEVER_INLINE
sieht aus wie:
#if \
HEDLEY_GNUC_HAS_ATTRIBUTE(noinline,4,0,0) || \
HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
HEDLEY_TI_VERSION_CHECK(8,0,0) || \
(HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
# define HEDLEY_NEVER_INLINE __attribute__((__noinline__))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
# define HEDLEY_NEVER_INLINE __declspec(noinline)
#elif HEDLEY_PGI_VERSION_CHECK(10,2,0)
# define HEDLEY_NEVER_INLINE _Pragma("noinline")
#elif HEDLEY_TI_VERSION_CHECK(6,0,0)
# define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
#else
# define HEDLEY_NEVER_INLINE HEDLEY_INLINE
#endif
Wenn Sie Hedley nicht verwenden möchten (es ist ein einziger Public Domain / CC0-Header), können Sie die Makros zur Versionsprüfung ohne allzu großen Aufwand konvertieren, aber mehr, als ich bereit bin zu investieren ☺.
Eine portable Möglichkeit, dies zu tun, besteht darin, die Funktion über einen Zeiger aufzurufen:
void (*foo_ptr)() = foo;
foo_ptr();
Dies erzeugt jedoch andere Anweisungen zum Verzweigen, was möglicherweise nicht Ihr Ziel ist. Was einen guten Punkt aufwirft: was ist Ihr Ziel hier?
Falls Sie einen Compiler-Fehler für __attribute__((noinline))
du kannst es einfach versuchen:
noinline int func(int arg)
{
....
}
static __attribute__ ((noinline)) void foo()
{
}
Das hat bei mir funktioniert.
Verwenden Sie die noinline
Attribut:
int func(int arg) __attribute__((noinline))
{
}
Sie sollten es wahrscheinlich sowohl beim Deklarieren der Funktion für die externe Verwendung als auch beim Schreiben der Funktion verwenden.
Danke für diese Frage! Ich habe mit oprofile ein Profil erstellt, als eine Funktion nicht angezeigt wurde. Die Antworten hier haben dies behoben.
– Simon A. Eugster
29. Oktober 2011 um 9:17 Uhr
c++: stackoverflow.com/questions/3329214/…
– Ciro Santilli OurBigBook.com
17. Februar 2020 um 14:06 Uhr