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

时间:2010-07-01 18:10:20

标签: c embedded inline-code multiple-definition-error greenhills

链接器报告内联函数的多重定义错误。

我在头文件中有以下代码:

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;
}

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

我希望上面的函数粘贴内联,无论它在哪里调用 是否有一种技术可以在每个源文件中包含多个函数定义? 如果是,请提供示例。

我需要针对嵌入式平台进行性能优化 编译器或链接器是否足够聪明,可以在其他翻译单元中定义内联函数?

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

5 个答案:

答案 0 :(得分:4)

内联只是一个建议,而不是一个命令。然而,总的来说,编译器足够聪明,可以做正确的事情(Green Hills在优化方面具有良好的声誉)。

使函数'static inline',这将阻止编译器使符号可导出。这应该修复你的多个定义链接错误...链接器抱怨从几个源模块导出相同的函数。

答案 1 :(得分:0)

一些重要的注释:

您似乎没有正确保护标题。

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

当标题为#include d多次时,这会阻止多个定义。

您似乎也认为可以强制编译器内联您的函数。这是不正确的。抛开一个疯狂而模糊的编译器标志,编译器将始终决定是否要在生成的代码中内联函数。内联关键字的含义/目的与您的想法不同,请参阅here

答案 2 :(得分:0)

目前尚不清楚为什么“2000之前的C语言规范” - 最后一个标准于1999年定稿。在此之前,inline根本不是关键字。

1999年的标准有这样的说法:

  

如果所有文件范围声明   用于翻译单元中的功能   包括inline函数   没有extern的说明符,然后是   该翻译单位的定义是   内联定义。内联   定义不提供   函数的外部定义,   并且不禁止外部   另一种翻译中的定义   单元。内联定义提供了一个   替代外部定义,   译者可能会使用哪一个   实现对函数的任何调用   相同的翻译单位。它是   未指定是否致电   函数使用内联定义或   外部定义。

这意味着只要你没有Write_Port_Pin() extern限定符的声明,编译器就不应该生成函数的外部定义,所以它不应该打扰链接器。如果我是你,我会把这个提交给你的编译器供应商。

答案 3 :(得分:0)

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

为避免这种情况,可以使用--c99选项代替--gnu。

并且由于编译器导出内联函数而摆脱.c文件中的这个多重定义问题。

答案 4 :(得分:-1)

在C中,您无法在多个位置定义具有相同名称的函数,无论它是否为内联函数。

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

/* 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);

然后在一个地方定义.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;                     
} 

然后在所有调用该函数的.c文件中#include此头文件。