使用内线函数乘以定义的链接器错误
-
01-10-2019 - |
题
链接器正在报告内联函数的乘积定义错误。
我在标头文件中有以下代码:
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平台上使用绿色山丘编译器,4.2.4。假设2000 C之前的语言标准。这是C代码而不是C ++。
解决方案
内联只是一个建议,而不是命令。但是,总的来说,编译器足够聪明,可以做正确的事情(在优化方面,Green Hills在良好的声誉中享有良好的声誉)。
使功能“静态直列”,这将防止编译器使符号可导出。应该修复您的多个定义链接错误...链接器抱怨说,相同的功能是从多个源模块导出的。
其他提示
一些重要说明:
看来您没有适当地保护标头。
#ifndef NAME_H
#define NAME_H
//...contents go here...
#endif // NAME_H
当标题为时,这会防止多个定义 #include
D不止一次。
似乎您认为您可以强迫编译器内联功能。这是不正确的。除了疯狂而晦涩的编译器标志之外,编译器将始终决定是否要在生产的代码中嵌入您的功能。内联关键词的含义/目的与您的想法不同,请参见 这里
目前尚不清楚您的意思是为什么“ 2000 C语言规范” - 最后一个标准于1999年完成。在此之前, inline
根本不是关键字。
1999年的标准可以说:
如果翻译单元中函数的所有文件范围声明包括
inline
功能指示符没有extern
, ,然后该翻译单元中的定义是 内联定义. 。内联定义不能为该功能提供外部定义,也不禁止在另一个翻译单元中进行外部定义。内联定义提供了外部定义的替代方案,转换器可以用该定义在同一翻译单元中实现对该功能的任何调用。是否使用对该函数的调用使用内联定义或外部定义是未指定的。
这意味着只要您没有声明 Write_Port_Pin()
与 extern
资格仪,编译器不应生成该功能的外部定义,因此它不应打扰链接器。如果我是您的话,我会将其作为错误供应商。
如果您在.h文件中具有内联定义,并且将其包含在许多.C文件中,并尝试使用ARMCC编译器编译LIB。现在,如果您使用-gnu编译器选项来编译ARMCC代码,那么您还会在链接时看到乘法定义错误,因为然后编译器将定义放在每个.c文件中并导出它。似乎在试图使您的代码GCC兼容时,我们得到了这个缺点。
为避免它,可以使用-C99选项,而不是-gnu。
并因编译器的内联函数导出而在.c文件中摆脱此倍数定义问题。
在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);
然后在一个位置中定义函数:
/* 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文件中#crude此标头文件。