代码之家  ›  专栏  ›  技术社区  ›  Thomas Matthews

使用内联函数的多重定义链接器错误

  •  1
  • Thomas Matthews  · 技术社区  · 14 年前

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

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

    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平台上使用GreenHills编译器4.2.4。采用2000年以前的C语言标准。这是C代码而不是C++。

    5 回复  |  直到 10 年前
        1
  •  4
  •   Chris Arguin    14 年前

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

    使函数“static inline”,这将阻止编译器使符号可导出。这样可以修复多个定义链接错误…链接器抱怨同一个函数是从几个源模块导出的。

        2
  •  0
  •   Community Egal    7 年前

    一些重要注意事项:

    似乎你没有正确地保护你的头部。

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

    这样可以防止在头为 #include D不止一次。

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

        3
  •  0
  •   caf    14 年前

    你所说的“2000年以前的C语言规范”(上一个标准是在1999年最终确定的)是什么意思还不清楚。在此之前, inline 根本不是关键字。

    1999年标准规定:

    如果所有文件范围声明 对于翻译单元中的函数 包括 内联的 功能 不带说明符 extern 然后 翻译单元中的定义是 安 内联定义 . 内联 定义不提供 函数的外部定义, 也不禁止外部 另一种翻译中的定义 单位。内联定义提供 替代外部定义, 翻译可以用来 在中实现对函数的任何调用 相同的翻译单元。它是 未指定是否调用 函数使用内联定义或 外部定义。

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

        4
  •  0
  •   ashish    11 年前

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

    为了避免这种情况,可以使用--c99选项而不是--gnu。

    并且消除了在.c文件中由于编译器导出内联函数而导致的这种乘法定义问题。

        5
  •  -1
  •   BenMorel lsalamon    10 年前

    在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文件中。