链接器报告内联函数的多重定义错误。
我在头文件中有以下代码:
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 ++。
答案 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此头文件。