使用内联函数乘以定义的链接器错误

时间:2022-08-24 16:28:29

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.

我将头文件包含在多个源文件(.c)中。

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++.

我正在使用Green Hills编译器,4.2.4在嵌入式ARM9平台上。采用2000年以前的C语言标准。这是C代码,不是c++。

5 个解决方案

#1


4  

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 ).

内联只是一个建议,而不是命令。然而,在一般情况下,编译器足够聪明,可以做正确的事情(就优化而言,Green Hills有着良好的声誉)。

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.

使函数“静态内联”,这将阻止编译器使符号可导出。这应该可以修复你的多重定义链接错误……链接器抱怨同样的功能是从几个源模块导出的。

#2


0  

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

您似乎还认为可以强制编译器内联您的函数。这是不正确的。除了一个疯狂而模糊的编译器标志,编译器总是会决定是否要在生成的代码中内联您的函数。内联关键字的含义/目的与您所想的不同,请参见这里

#3


0  

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.

不清楚您的意思是为什么“2000年以前的C语言规范”——最后一个标准是1999年制定的。在此之前,inline根本不是一个关键字。

The 1999 standard has this to say:

1999年的标准是:

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.

如果转换单元中函数的所有文件范围声明都包含不带extern的内联函数说明符,那么转换单元中的定义就是内联定义。内联定义不为函数提供外部定义,也不禁止在另一个翻译单元中使用外部定义。内联定义提供了外部定义的替代方法,译者可以使用它来实现对同一翻译单元中的函数的任何调用。对函数的调用是使用内联定义还是使用外部定义是不确定的。

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.

这意味着,只要您没有使用externn限定符声明Write_Port_Pin(),编译器就不应该生成函数的外部定义,因此不应该影响链接器。如果我是你的话,我会把它作为一个bug提交给你的编译器供应商。

#4


0  

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.

如果在.h文件中有内联定义,并将其包含在许多.c文件中,并尝试使用armcc编译器编译库。现在,如果您使用-gnu编译器选项来编译armcc代码,那么您还会看到在链接时的乘法定义错误,因为编译器会在每个.c文件中放入定义并导出它。似乎在尝试使您的代码兼容GCC时,我们得到了这个缺点。

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

为了避免它,可以使用c99选项而不是gnu。

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

并摆脱了在.c文件中由于编译器导出内联函数而产生的乘法定义问题。

#5


-1  

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

在C语言中,无论是否内联,都不能在多个地方定义具有相同名称的函数。

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

处理此问题的最佳方法是在header中声明函数(以及它所依赖的结构定义,如下所示:

/* 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:

然后在一个地方定义.c源文件中的函数:

/* 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.

然后在所有调用该函数的.c文件中包含这个头文件。

#1


4  

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 ).

内联只是一个建议,而不是命令。然而,在一般情况下,编译器足够聪明,可以做正确的事情(就优化而言,Green Hills有着良好的声誉)。

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.

使函数“静态内联”,这将阻止编译器使符号可导出。这应该可以修复你的多重定义链接错误……链接器抱怨同样的功能是从几个源模块导出的。

#2


0  

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

您似乎还认为可以强制编译器内联您的函数。这是不正确的。除了一个疯狂而模糊的编译器标志,编译器总是会决定是否要在生成的代码中内联您的函数。内联关键字的含义/目的与您所想的不同,请参见这里

#3


0  

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.

不清楚您的意思是为什么“2000年以前的C语言规范”——最后一个标准是1999年制定的。在此之前,inline根本不是一个关键字。

The 1999 standard has this to say:

1999年的标准是:

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.

如果转换单元中函数的所有文件范围声明都包含不带extern的内联函数说明符,那么转换单元中的定义就是内联定义。内联定义不为函数提供外部定义,也不禁止在另一个翻译单元中使用外部定义。内联定义提供了外部定义的替代方法,译者可以使用它来实现对同一翻译单元中的函数的任何调用。对函数的调用是使用内联定义还是使用外部定义是不确定的。

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.

这意味着,只要您没有使用externn限定符声明Write_Port_Pin(),编译器就不应该生成函数的外部定义,因此不应该影响链接器。如果我是你的话,我会把它作为一个bug提交给你的编译器供应商。

#4


0  

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.

如果在.h文件中有内联定义,并将其包含在许多.c文件中,并尝试使用armcc编译器编译库。现在,如果您使用-gnu编译器选项来编译armcc代码,那么您还会看到在链接时的乘法定义错误,因为编译器会在每个.c文件中放入定义并导出它。似乎在尝试使您的代码兼容GCC时,我们得到了这个缺点。

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

为了避免它,可以使用c99选项而不是gnu。

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

并摆脱了在.c文件中由于编译器导出内联函数而产生的乘法定义问题。

#5


-1  

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

在C语言中,无论是否内联,都不能在多个地方定义具有相同名称的函数。

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

处理此问题的最佳方法是在header中声明函数(以及它所依赖的结构定义,如下所示:

/* 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:

然后在一个地方定义.c源文件中的函数:

/* 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.

然后在所有调用该函数的.c文件中包含这个头文件。