inline C functions?

Will
2011-05-04
2013-03-12
  • Will
    Will
    2011-05-04

    I've done a bit of Google-ing and everything I have found suggests that SDCC 3.0.0 should support inline C functions as long as I use either the -std-c99 or -std-sdcc99 options.  I cannot for the life of me get it to work.  :(

    Example:

    #include <8051.h>            // SFR declarations
    inline void init_foo(void);
    void main(void)
    {
        init_foo();
        while (1)
        {
            P0++;
        }
    }
    inline void init_foo(void)
    {
        P1 = 0xFF;
    }
    

    results in

    ?ASlink-Warning-Undefined Global '_init_foo' referenced by module 'main'

    My command line looks like:

    >sdcc --model-large --funsigned-char --std-sdcc99 main.c -o"out.ihx"
    

    I am using SDCC 3.3.0 #6037 (Oct 31 2010)  (MINGW32)

    If I removed the "inline" keywords (or stranger still, just remove the one from the actual function declaration but leave the one in front of the prototype) it compiles without a problem.  But then the function doesn't actually get inlined.  I even disassembled the file to make sure that the optimizer wasn't just inlining it anyway and it clearly makes an LCALL to the function and then returns to the main loop.

    Any ideas?

    -Will

     
  • Maarten Brock
    Maarten Brock
    2011-05-04

    Will,

    Can you please try again with a recent SDCC 3.0.2 snapshot? If it still fails please file this as a bug in the bug tracker.

    Maarten

     
  • Maarten Brock
    Maarten Brock
    2011-05-05

    If you define init_foo before main it gets inlined, if you only declare it with a prototype before main apparently it doesn't and main uses an LCALL. But then init_foo is not implemented after main either which leads to the undefined global.

    I'm not sure what the standard says about declaring an inline function without defining it before use.

     
  • Will
    Will
    2011-05-05

    If you define init_foo before main it gets inlined, if you only declare it with a prototype before main apparently it doesn't and main uses an LCALL. But then init_foo is not implemented after main either which leads to the undefined global. I'm not sure what the standard says about declaring an inline function without defining it before use.

    I'm not sure I understand what you are describing.  If I replace the prototype with the actual function body, I still get the ASlink error.

    #include <stdint.h>
    #include <8051.h>            // SFR declarations
    inline void init_foo(void)
    {
        P1 = 0xFF;
    }
    void main(void)
    {
        init_foo();
        while (1)
        {
            P0++;
        }
    }
    

    My problem is even more complex than this simple example because I am trying to have a separate library with lots of these little inline functions and then call them from other source files.  In that case there is no "before" or "after" during compilation, the linker just gets passed a bunch of .rel files.
    -Will

     
  • Maarten Brock
    Maarten Brock
    2011-05-05

    Yes, that's what I meant. And if I compile that with SDCC 3.0.2 it is properly inlined. See the generated .asm.

    However init_foo is not implemented separately and I do get this linker error. This is because init_foo is a so-called inline definition (it is not marked extern) and has external linkage. This means it must be implemented in another module.

    Now if I make init_foo static to remove the external linkage everything works fine, but init_foo is implemented while it need not be. This is because the compiler does not yet recognize that it isn't used in a function pointer.

    static inline void init_foo(void)
    {
        P1 = 0xFF;
    }
    void main(void)
    {
        init_foo();
        while (1)
        {
            P0++;
        }
    }
    

    If the definition of the inline function is outside the view of the compiler it cannot be inlined. The linker will not replace inline code. This is required by the standard.

    I recommend to implement the inline function with static keyword in a header file if you want to use it in several source files.

     
  • Maarten Brock
    Maarten Brock
    2011-05-05

    Another option is to define them in a header file without static and implement them once in one module with extern.

    inlines.h

    inline void init_foo(void)
    {
        P1 = 0xFF;
    }
    

    inlines.c

    // external definitions for inline functions
    #include "inlines.h" // to make sure the prototype matches
    extern inline void init_foo(void)
    {
        P1 = 0xFF; // you could even leave this definition empty if you want
    }
    

    main.c

    #include "inlines.h"
    void main(void)
    {
        init_foo();
        while (1)
        {
            P0++;
        }
    }
    
     
  • Will
    Will
    2011-05-05

    Forgive me if this is a naive question but what would be the point of declaring the body of init_foo in an H file and then in a C file as well?  Wouldn't it make more sense to just have the H file definition and leave out the C file altogether?

    -Will

     
  • Maarten Brock
    Maarten Brock
    2011-05-05

    That is a question for the C standardization committee. N1124 ISO/IEC 9899 TC2 clearly states in 6.7.4 points 6, 7 & 8 that it needs an external definition.