Rozumiem, że inline
samo w sobie jest sugestią dla kompilatora i według własnego uznania może wbudować funkcję lub nie, a także wygeneruje kod wynikowy, który można połączyć.
Myślę, że static inline
robi to samo (może być wbudowane lub nie), ale po wstawieniu nie utworzy kodu wynikowego, który można połączyć (ponieważ żaden inny moduł nie może się z nim połączyć).
Gdzie to extern inline
pasuje do obrazu?
Załóżmy, że chcę zastąpić makro preprocesora funkcją wbudowaną i wymagam, aby ta funkcja została wbudowana (np. Ponieważ używa makr __FILE__
i, __LINE__
które powinny być rozwiązywane dla wywołującego, ale nie tej wywoływanej funkcji). Oznacza to, że chcę zobaczyć błąd kompilatora lub konsolidatora na wypadek, gdyby funkcja nie została wstawiona. Czy extern inline
to robi? (Zakładam, że jeśli tak nie jest, nie ma innego sposobu na osiągnięcie tego zachowania niż trzymanie się makra).
Czy są różnice między C ++ i C?
Czy istnieją różnice między różnymi dostawcami i wersjami kompilatorów?
źródło
extern inline
podlega regule jednej definicji i to jest definicja. Ale jeśli heurystyka optymalizacji zdefiniowana w ramach implementacji jest zgodna z zaleceniem użyciainline
słowa kluczowego jako sugestii, że „wywołania funkcji powinny być tak szybkie, jak to możliwe” (ISO 9899: 1999 §6.7.4 (5),extern inline
liczy sięUważam, że źle zrozumiałeś __FILE__ i __LINE__ na podstawie tego stwierdzenia:
Istnieje kilka faz kompilacji, a pierwszą jest przetwarzanie wstępne. __FILE__ i __LINE__ są zastępowane podczas tej fazy. Więc zanim kompilator będzie mógł rozważyć funkcję wstawiania, zostały one już zastąpione.
źródło
Wygląda na to, że próbujesz napisać coś takiego:
inline void printLocation() { cout <<"You're at " __FILE__ ", line number" __LINE__; } { ... printLocation(); ... printLocation(); ... printLocation();
i mając nadzieję, że za każdym razem otrzymasz inne wartości. Jak mówi Don, nie zrobisz tego, ponieważ __FILE__ i __LINE__ są implementowane przez preprocesor, ale wbudowane są implementowane przez kompilator. Więc gdziekolwiek wywołasz printLocation, otrzymasz ten sam wynik.
Tylko sposób można uzyskać to do pracy jest, aby printLocation makro. (Tak, wiem...)
#define PRINT_LOCATION {cout <<"You're at " __FILE__ ", line number" __LINE__} ... PRINT_LOCATION; ... PRINT_LOCATION; ...
źródło
Sytuacja z inline, static inline i extern inline jest skomplikowana, nie tylko dlatego, że gcc i C99 definiują nieco inne znaczenia ich zachowania (i prawdopodobnie również C ++). Możesz znaleźć przydatne i szczegółowe informacje o tym, co robią w C. tutaj .
źródło
Zamiast funkcji wbudowanych wybierasz makra. Rzadka sytuacja, w której makra rządzą funkcjami wbudowanymi. Spróbuj wykonać następujące czynności: napisałem ten kod „MAGIA MAKRO” i powinien działać! Przetestowano na 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; }
W przypadku wielu plików zdefiniuj te makra w osobnym pliku nagłówkowym, w tym to samo w każdym pliku c / cc / cxx / cpp. Jeśli to możliwe, preferuj funkcje wbudowane lub identyfikatory stałych (zgodnie z wymaganiami) zamiast makr.
źródło
Zamiast odpowiadać „co to robi?”, Odpowiadam „jak mam zrobić to, co chcę?” Istnieje 5 rodzajów wstawiania, wszystkie dostępne w GNU C89, standardowym C99 i C ++:
zawsze w tekście, chyba że adres jest zajęty
Dodaj
__attribute__((always_inline))
do dowolnej deklaracji, a następnie użyj jednego z poniższych przypadków, aby obsłużyć możliwość pobrania jej adresu.Prawdopodobnie nigdy nie powinieneś tego używać, chyba że potrzebujesz jego semantyki (np. Aby wpłynąć na asemblację w określony sposób lub użyć
alloca
). Kompilator zwykle wie lepiej od Ciebie, czy warto.w tekście i emitują słaby symbol (np. C ++, czyli „po prostu zrób to”)
__attribute__((weak)) void foo(void); inline void foo(void) { ... }
Zauważ, że pozostawia to kilka kopii tego samego kodu, a linker wybiera jeden arbitralnie.
inline, ale nigdy nie emituj żadnego symbolu (pozostawiając odnośniki zewnętrzne)
__attribute__((gnu_inline)) extern inline void foo(void) { ... }
emituj zawsze (dla jednej jednostki tłumaczeniowej, aby rozwiązać poprzedni)
Wersja ze wskazówkami emituje słaby symbol w C ++, ale silny symbol w każdym dialekcie C:
void foo(void); inline void foo(void) { ... }
Lub możesz to zrobić bez podpowiedzi, która emituje silny symbol w obu językach:
void foo(void) { ... }
Generalnie wiesz, jakim językiem jest Twoja jednostka językowa, kiedy podajesz definicje, i prawdopodobnie nie potrzebujesz zbyt wiele wstawiania.
inline i emituj w każdej jednostce tłumaczeniowej
static inline void foo(void) { ... }
Dla wszystkich z wyjątkiem
static
jednego, możesz dodaćvoid foo(void)
deklarację powyżej. Pomaga to w „najlepszej praktyce” pisania czystych nagłówków, a następnie#include
tworzenia oddzielnego pliku z definicjami w wierszu. Jeśli korzystasz z wbudowanych w stylu C,#define
niektóre makra inaczej w jednej dedykowanej jednostce tłumaczeniowej, aby zapewnić definicje poza linią.Nie zapomnij,
extern "C"
jeśli nagłówek może być używany zarówno z C, jak i C ++!źródło
nm
odpowiednik.