Question

The linker is reporting multiply defined errors for an inline function.

I have the following code in a header file:

struct Port_Pin
{
    volatile uint32_t *     port_addr_set_value;    //!< Writing the pin value here sets the pin to high.
    volatile uint32_t *     port_addr_clr_value;    //!< Writing the pin value to this port clears the pin to low.
    volatile uint32_t *     port_addr_read_value;   //!< Address to read pin value.
    volatile uint32_t *     port_addr_enable;       //!< Writing the pin value here enables the pin (for reading or writing).
    volatile uint32_t *     port_addr_disable;      //!< Writing the pin value here disables the pin.
    volatile uint32_t *     port_addr_dir_output;   //!< Writing the pin value here sets the pin as an output.
    volatile uint32_t *     port_addr_dir_input;    //!< Writing the pin value here sets the pin as an input.
    unsigned int            pin_bit_position;       //!< Zero based, where position zero is first bit position.
};

inline void
Write_Port_Pin(const struct Port_Pin *  p_port,
               uint8_t                  bit)
{
    volatile uint32_t * port_addr = 0;
    port_addr = ((bit & 1) == 0) ? p_port->port_addr_clr_value
        : p_port->port_addr_set_value;
    *port_addr = 1 << p_port->pin_bit_position;
    return;
}

I include the header file in more than one source (.c) file.

I would like to have the above function pasted inline wherever it is called.
Is there a technique for this without have multiple definitions of the function in each source file that is included? If yes, please provide example.

I need the performance optimization for an embedded platform.
Are compilers or linkers smart enough to inline functions when they are defined in other translation units?

I am using Green Hills compiler, 4.2.4 on an embedded ARM9 platform. Assume pre-2000 C language standard. This is C code not C++.

Was it helpful?

Solution

inline is just a suggestion, not a command. However, in general compilers are smart enough to do the right thing ( and Green Hills has a good reputation in so far as optimizations go ).

Make the function 'static inline', which will prevent the compiler from making the symbol exportable. That should fix your multiple definition link errors... the linker is complaining that the same function is exported from several source modules.

OTHER TIPS

Some important notes:

It seems that you did not properly guard your header.

#ifndef NAME_H
#define NAME_H
//...contents go here...
#endif // NAME_H

This prevents multiple definitions when the header is #included more than once.

It also seems like you think that you can force a compiler to inline your function. This is not correct. A crazy and obscure compiler flag aside, the compiler will always decide if it wants to inline your function in the produced code. The inline keyword has a different meaning/purpose than what you think, see here

It's not clear what you mean why "pre-2000 C language specification" - the last standard was finalised in 1999. Prior to that, inline wasn't a keyword at all.

The 1999 standard has this to say:

If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.

This means that as long as you don't have a declaration of Write_Port_Pin() with the extern qualifier, the compiler shouldn't generate an external definition of the function, so it shouldn't bother the linker. I'd submit this as a bug to your compiler vendor if I were you.

If you have inline definition in .h file and you include it in many .c files and try to compile a lib using armcc compiler. Now If you use --gnu compiler option to compile armcc code then also you see multiply define error while linking, because then compiler puts definition in each .c file and exports it. It seems while trying to make your code GCC compatible, we get this drawback.

To avoid it, may be use --c99 option instead of --gnu.

and get rid of this multiply define issue in .c files due to inline functions export by compiler.

In C you cannot define a function with the same name in multiple places whether it is inline or not.

The best way to handle this is to declare the function in a header (along with the structure definition it depends on, like so:

/* port_control.h */

struct Port_Pin              
{              
    volatile uint32_t *     port_addr_set_value;    //!< Writing the pin value here sets the pin to high.              
    volatile uint32_t *     port_addr_clr_value;    //!< Writing the pin value to this port clears the pin to low.              
    volatile uint32_t *     port_addr_read_value;   //!< Address to read pin value.              
    volatile uint32_t *     port_addr_enable;       //!< Writing the pin value here enables the pin (for reading or writing).              
    volatile uint32_t *     port_addr_disable;      //!< Writing the pin value here disables the pin.              
    volatile uint32_t *     port_addr_dir_output;   //!< Writing the pin value here sets the pin as an output.              
    volatile uint32_t *     port_addr_dir_input;    //!< Writing the pin value here sets the pin as an input.              
    unsigned int            pin_bit_position;       //!< Zero based, where position zero is first bit position.              
};              

/* Declare the function here so other modules know about it. */        
inline void              
Write_Port_Pin(const struct Port_Pin *  p_port,              
               uint8_t                  bit);

Then define the function in a .c source file in one place:

/* port_control.c */

#include "port_control.h"

inline void                     
Write_Port_Pin(const struct Port_Pin *  p_port,                     
               uint8_t                  bit)                     
{                     
    volatile uint32_t * port_addr = 0;                     
    port_addr = ((bit & 1) == 0) ? p_port->port_addr_clr_value                     
        : p_port->port_addr_set_value;                     
    *port_addr = 1 << p_port->pin_bit_position;                     
    return;                     
} 

Then #include this header file in all of the .c files that call the function.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top