1

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

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

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

4

5 回答 5

4

inline 只是一个建议,而不是命令。但是,通常编译器足够聪明,可以做正确的事情(就优化而言,Green Hills 享有良好的声誉)。

使函数“静态内联”,这将阻止编译器使符号可导出。那应该可以解决您的多个定义链接错误...链接器抱怨从多个源模块导出了相同的函数。

于 2010-07-01T18:27:15.450 回答
0

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

1999 年的标准是这样说的:

如果翻译单元中函数的所有文件范围声明都包含inline函数说明符 without extern,则该翻译单元中的定义是内联定义。内联定义不为函数提供外部定义,也不禁止在另一个翻译单元中进行外部定义。内联定义提供了外部定义的替代方案,翻译器可以使用它来实现对同一翻译单元中函数的任何调用。未指定对函数的调用是使用内联定义还是外部定义。

这意味着只要您没有Write_Port_Pin()使用extern限定符声明,编译器就不应生成函数的外部定义,因此它不应该打扰链接器。如果我是您,我会将其作为错误提交给您的编译器供应商。

于 2010-07-02T02:52:05.940 回答
0

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

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

由于编译器导出了内联函数,因此在 .c 文件中摆脱了这个多重定义问题。

于 2013-04-12T16:32:37.527 回答
0

一些重要的注意事项:

看来您没有正确保护您的标题。

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

当标头#included 不止一次时,这可以防止多个定义。

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

于 2010-07-01T18:27:57.157 回答
-1

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.

于 2010-07-01T18:36:36.413 回答