What does extern inline do?

后端 未结 6 2074
闹比i
闹比i 2020-11-22 12:07

I understand that inline by itself is a suggestion to the compiler, and at its discretion it may or may not inline the function, and it will also produce linkab

相关标签:
6条回答
  • 2020-11-22 12:17

    Macros are your choice here rather than the inline functions. A rare occasion where macros rule over inline functions. Try the following: I wrote this "MACRO MAGIC" code and it should work! Tested on 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;
    }
    

    For multiple files define these macros in a separate header file including the same in each c/cc/cxx/cpp files. Please prefer inline functions or const identifiers (as the case demands) over macros wherever possible.

    0 讨论(0)
  • 2020-11-22 12:22

    The situation with inline, static inline and extern inline is complicated, not least because gcc and C99 define slightly different meanings for their behavior (and presumably C++, as well). You can find some useful and detailed information about what they do in C here.

    0 讨论(0)
  • 2020-11-22 12:23

    in K&R C or C89, inline was not part of the language. Many compilers implemented it as an extension, but there were no defined semantics regarding how it worked. GCC was among the first to implement inlining, and introduced the inline, static inline, and extern inline constructs; most pre-C99 compiler generally follow its lead.

    GNU89:

    • inline: the function may be inlined (it's just a hint though). An out-of-line version is always emitted and externally visible. Hence you can only have such an inline defined in one compilation unit, and every other one needs to see it as an out-of-line function (or you'll get duplicate symbols at link time).
    • extern inline will not generate an out-of-line version, but might call one (which you therefore must define in some other compilation unit. The one-definition rule applies, though; the out-of-line version must have the same code as the inline offered here, in case the compiler calls that instead.
    • static inline will not generate a externally visible out-of-line version, though it might generate a file static one. The one-definition rule does not apply, since there is never an emitted external symbol nor a call to one.

    C99 (or GNU99):

    • inline: like GNU89 "extern inline"; no externally visible function is emitted, but one might be called and so must exist
    • extern inline: like GNU89 "inline": externally visible code is emitted, so at most one translation unit can use this.
    • static inline: like GNU89 "static inline". This is the only portable one between gnu89 and c99

    C++:

    A function that is inline anywhere must be inline everywhere, with the same definition. The compiler/linker will sort out multiple instances of the symbol. There is no definition of static inline or extern inline, though many compilers have them (typically following the gnu89 model).

    0 讨论(0)
  • 2020-11-22 12:37

    I believe you misunderstand __FILE__ and __LINE__ based on this statement:

    because it uses the __FILE__ and __LINE__ macros which should resolve for the caller but not this called function

    There are several phases of compilation, and preprocessing is the first. __FILE__ and __LINE__ are replaced during that phase. So by the time the compiler can consider the function for inlining they have already been replaced.

    0 讨论(0)
  • 2020-11-22 12:37

    It sounds like you're trying to write something like this:

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

    and hoping that you'll get different values printed each time. As Don says, you won't, because __FILE__ and __LINE__ are implemented by the preprocessor, but inline is implemented by the compiler. So wherever you call printLocation from, you'll get the same result.

    The only way you can get this to work is to make printLocation a macro. (Yes, I know...)

    #define PRINT_LOCATION  {cout <<"You're at " __FILE__ ", line number" __LINE__}
    
    ...
      PRINT_LOCATION;
    ...
      PRINT_LOCATION;
    ...
    
    0 讨论(0)
  • 2020-11-22 12:40

    Instead of answering "what does it do?", I'm answering "how do I make it do what I want?" There are 5 kinds of inlining, all available in GNU C89, standard C99, and C++:

    always inline, unless the address is taken

    Add __attribute__((always_inline)) to any declaration, then use one of the below cases to handle the possibility of its address being taken.

    You should probably never use this, unless you need its semantics (e.g. to affect the assembly in a certain way, or to use alloca). The compiler usually knows better than you whether it's worth it.

    inline and emit a weak symbol (like C++, aka "just make it work")

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

    Note that this leaves a bunch of copies of the same code lying around, and the linker picks one arbitrarily.

    inline, but never emit any symbol (leaving external references)

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

    emit always (for one TU, to resolve the preceding)

    The hinted version emits a weak symbol in C++, but a strong symbol in either dialect of C:

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

    Or you can do it without the hint, which emits a strong symbol in both languages:

    void foo(void) { ... }
    

    Generally, you know what language your TU is when you're providing the definitions, and probably don't need much inlining.

    inline and emit in every TU

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

    For all of these except the static one, you can add a void foo(void) declaration above. This helps with the "best practice" of writing clean headers, then #includeing a separate file with the inline definitions. Then, if using C-style inlines, #define some macro differently in one dedicated TU to provide the out-of-line definitions.

    Don't forget extern "C" if the header might be used from both C and C++!

    0 讨论(0)
提交回复
热议问题