"multiple definition of first defined here"。 STM32、AC6工作室
"multiple definition of first defined here". STM32, AC6 Studio
我遇到了一个愚蠢的问题,尽管一切都必须正常运行。我的任务是 - 使用联合和结构的数据类型初始化 I/O 寄存器。我在初始化时只使用了我的名字,这样我就可以避免因重新定义系统变量而导致的错误。但是,编译器仍然向我显示我创建的所有变量的错误,因为它们已在项目的其他地方初始化。有我的变量初始化代码:
volatile SYSCFG_t* mysyscfg=(volatile SYSCFG_t*)MYSYSCFG;
volatile RCC_AHB2ENR_t* myrcc_ahb2enr=(volatile RCC_AHB2ENR_t*)(MYRCC|MYAHB2ENR_OFFS);
volatile RCC_APB2ENR_t* myrcc_apb2enr=(volatile RCC_APB2ENR_t*)(MYRCC|MYAPB2ENR_OFFS);
volatile GPIO_t* mygpiob=(volatile GPIO_t*)MYGPIOB;
volatile GPIO_t* mygpioe=(volatile GPIO_t*)MYGPIOE;
volatile GPIO_t* mygpioa=(volatile GPIO_t*)MYGPIOA;
我犯的错误如下:
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:262: multiple definition of `mysyscfg'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:262: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:263: multiple definition of `myrcc_ahb2enr'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:263: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:264: multiple definition of `myrcc_apb2enr'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:264: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:265: multiple definition of `mygpiob'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:265: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:266: multiple definition of `mygpioe'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:266: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:267: multiple definition of `mygpioa'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:267: first defined here
collect2: error: ld returned 1 exit status
make: *** [makefile:62: timers.elf] Error 1
这些是链接器错误。你可能正在做这样的事情:
main.c:
#include "lib.h"
init.c:
#include "lib.h"
当链接器检查 main.c 和 init.c 中的符号和类型时,它发现它们中的每一个都定义了完全相同的符号,因此出现错误。通常 header 文件只声明符号,不定义它们,但是条件代码有一些创造性的用途可以解决这个问题:
lib.h(请为该文件想一个更具描述性的名称)
#if defined IN_INIT_C
volatile SYSCFG_t* mysyscfg=(volatile SYSCFG_t*)MYSYSCFG; // Definition
#else
extern volatile SYSCFG_T* mysyscfg; // Declaration
#endif
现在在 init.c 并且只在那个文件中:
#define IN_INIT_C
#include "lib.h"
或者您可以简单地将定义放在 init.c 中,并通过仅在其中放置声明来简化您的 header。
您还应该阅读此搜索提供的问答:
https://whosebug.com/search?q=%5Bc%5Ddifference+between+declaration+and+definition
在 include-file 中定义变量是个坏主意。原因是您无法将 include-file 包含在多个 c-file 中。如果这样做,您将得到现在的错误。
因此 您发布的代码应移至 c-file 并在 include-file 中您只需输入:
extern volatile SYSCFG_t* mysyscfg;
extern volatile RCC_AHB2ENR_t* myrcc_ahb2enr;
extern volatile RCC_APB2ENR_t* myrcc_apb2enr;
extern volatile GPIO_t* mygpiob;
extern volatile GPIO_t* mygpioe;
extern volatile GPIO_t* mygpioa;
然后 include-file 可以毫无问题地包含在多个 c-file 中。
正如其他人所说,不要在 header 文件中定义 object 或函数(static inline
除外)。
您还尝试重新发明轮子 - 所有寄存器定义都已经在 STM 提供的 CMSIS 文件中。
你的方法也很低效。当您访问您的变量时,它会生成不必要的代码。
#include <stdint.h>
#define __IO volatile
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
volatile GPIO_TypeDef *MYGPIOA = (volatile GPIO_TypeDef *)0x40000000;
#define GPIOA ((GPIO_TypeDef *)0x40000000)
void foo(uint32_t val)
{
MYGPIOA -> MODER = val;
}
void bar(uint32_t val)
{
GPIOA -> MODER = val;
}
如您所见,#define
方式生成的指令较少。这就是为什么在 CMSIS headers 中这样做的原因。您还不必要地为指针浪费内存。
foo:
ldr r3, .L3
ldr r3, [r3]
str r0, [r3]
bx lr
.L3:
.word .LANCHOR0
bar:
mov r3, #1073741824
str r0, [r3]
bx lr
MYGPIOA:
.word 1073741824
我遇到了一个愚蠢的问题,尽管一切都必须正常运行。我的任务是 - 使用联合和结构的数据类型初始化 I/O 寄存器。我在初始化时只使用了我的名字,这样我就可以避免因重新定义系统变量而导致的错误。但是,编译器仍然向我显示我创建的所有变量的错误,因为它们已在项目的其他地方初始化。有我的变量初始化代码:
volatile SYSCFG_t* mysyscfg=(volatile SYSCFG_t*)MYSYSCFG;
volatile RCC_AHB2ENR_t* myrcc_ahb2enr=(volatile RCC_AHB2ENR_t*)(MYRCC|MYAHB2ENR_OFFS);
volatile RCC_APB2ENR_t* myrcc_apb2enr=(volatile RCC_APB2ENR_t*)(MYRCC|MYAPB2ENR_OFFS);
volatile GPIO_t* mygpiob=(volatile GPIO_t*)MYGPIOB;
volatile GPIO_t* mygpioe=(volatile GPIO_t*)MYGPIOE;
volatile GPIO_t* mygpioa=(volatile GPIO_t*)MYGPIOA;
我犯的错误如下:
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:262: multiple definition of `mysyscfg'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:262: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:263: multiple definition of `myrcc_ahb2enr'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:263: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:264: multiple definition of `myrcc_apb2enr'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:264: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:265: multiple definition of `mygpiob'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:265: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:266: multiple definition of `mygpioe'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:266: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:267: multiple definition of `mygpioa'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:267: first defined here
collect2: error: ld returned 1 exit status
make: *** [makefile:62: timers.elf] Error 1
这些是链接器错误。你可能正在做这样的事情:
main.c:
#include "lib.h"
init.c:
#include "lib.h"
当链接器检查 main.c 和 init.c 中的符号和类型时,它发现它们中的每一个都定义了完全相同的符号,因此出现错误。通常 header 文件只声明符号,不定义它们,但是条件代码有一些创造性的用途可以解决这个问题:
lib.h(请为该文件想一个更具描述性的名称)
#if defined IN_INIT_C
volatile SYSCFG_t* mysyscfg=(volatile SYSCFG_t*)MYSYSCFG; // Definition
#else
extern volatile SYSCFG_T* mysyscfg; // Declaration
#endif
现在在 init.c 并且只在那个文件中:
#define IN_INIT_C
#include "lib.h"
或者您可以简单地将定义放在 init.c 中,并通过仅在其中放置声明来简化您的 header。
您还应该阅读此搜索提供的问答:
https://whosebug.com/search?q=%5Bc%5Ddifference+between+declaration+and+definition
在 include-file 中定义变量是个坏主意。原因是您无法将 include-file 包含在多个 c-file 中。如果这样做,您将得到现在的错误。
因此 您发布的代码应移至 c-file 并在 include-file 中您只需输入:
extern volatile SYSCFG_t* mysyscfg;
extern volatile RCC_AHB2ENR_t* myrcc_ahb2enr;
extern volatile RCC_APB2ENR_t* myrcc_apb2enr;
extern volatile GPIO_t* mygpiob;
extern volatile GPIO_t* mygpioe;
extern volatile GPIO_t* mygpioa;
然后 include-file 可以毫无问题地包含在多个 c-file 中。
正如其他人所说,不要在 header 文件中定义 object 或函数(static inline
除外)。
您还尝试重新发明轮子 - 所有寄存器定义都已经在 STM 提供的 CMSIS 文件中。
你的方法也很低效。当您访问您的变量时,它会生成不必要的代码。
#include <stdint.h>
#define __IO volatile
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
volatile GPIO_TypeDef *MYGPIOA = (volatile GPIO_TypeDef *)0x40000000;
#define GPIOA ((GPIO_TypeDef *)0x40000000)
void foo(uint32_t val)
{
MYGPIOA -> MODER = val;
}
void bar(uint32_t val)
{
GPIOA -> MODER = val;
}
如您所见,#define
方式生成的指令较少。这就是为什么在 CMSIS headers 中这样做的原因。您还不必要地为指针浪费内存。
foo:
ldr r3, .L3
ldr r3, [r3]
str r0, [r3]
bx lr
.L3:
.word .LANCHOR0
bar:
mov r3, #1073741824
str r0, [r3]
bx lr
MYGPIOA:
.word 1073741824