【问题标题】:Multiple definition of variables ESP32ESP32变量的多重定义
【发布时间】:2019-09-02 15:24:52
【问题描述】:

我正在为我的 ESP32 使用示例项目,我已将主 C 文件拆分为两个文件,main.cwifi.c,其中一个包含共享变量的头文件。

头文件:

#ifndef WIFI_TEST_H
#define WIFI_TEST_H

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"

#include "esp_system.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_flash_partitions.h"
#include "esp_partition.h"

#include "esp_wifi.h"
#include "esp_event_loop.h"

#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD

const char *TAG = "wifi_test";

/* FreeRTOS event group to signal when we are connected & ready to make a request */
EventGroupHandle_t wifi_event_group;
/* The event group allows multiple bits for each event,
   but we only care about one event - are we connected
   to the AP with an IP? */
const int CONNECTED_BIT = BIT0;

esp_err_t event_handler(void *, system_event_t *);
void initialise_wifi(void);

#endif

此文件包含在main.cwifi.c 中。 编译时,我收到以下错误:

/project/build/main/libmain.a(wifi.o):(.data.TAG+0x0): multiple definition of `TAG'
/project/build/main/libmain.a(main.o):(.data.TAG+0x0): first defined here
/project/build/main/libmain.a(wifi.o):(.rodata.CONNECTED_BIT+0x0): multiple definition of `CONNECTED_BIT'
/project/build/main/libmain.a(main.o):(.rodata.CONNECTED_BIT+0x0): first defined here

变量只在 h 文件中声明。我认为这可能是由于包括警卫,但它也不起作用。 我做了一个make clean 以确保没有留下任何旧的东西,仍然没有运气。

也许我只是忽略了一些微不足道的事情......

【问题讨论】:

  • 您在头文件中定义变量,这意味着它将在包含该头文件的所有translation units 中定义。而是在头文件中声明变量(使用extern 关键字并且不进行初始化),然后在单个源中定义(并初始化)变量。
  • 啊,解决了!我认为由于包含警卫,它只会被定义一次,但猜不是=)谢谢!
  • 包含保护用于在一个编译单元中重复包含。一个 cpp 的编译应该如何知道其他 cpp 中包含的内容?
  • @Someprogrammerdude 您似乎已经完全回答了这个问题。你会回答这个问题吗?

标签: c esp32


【解决方案1】:

接受并扩展了一些程序员老兄的评论,将这个问题从未回答的问题列表中删除。我相信他不介意,但提出要删除。

你在头文件中定义变量;请注意缺少 extern 关键字。 这里:

const char *TAG = "wifi_test";
const int CONNECTED_BIT = BIT0;

这意味着它将在包含该头文件的每个translation unit(简化:代码文件)中定义。
IE。您会为每个包含代码文件获得一个定义,即多个定义,即多个定义。这就是链接器通过您引用的错误消息告诉您的内容。

改为在头文件中声明变量(使用extern关键字且不初始化),即:

extern const char *TAG;
extern const int CONNECTED_BIT;

然后,仅在单个源文件中,定义(并初始化)变量,即:

/* only in one .c, not in a .h, that is the difference */
const char *TAG = "wifi_test";
const int CONNECTED_BIT = BIT0;

独特的代码文件部分使定义单一,没有倍数,让链接器满意。
同时,在编译所有其他代码文件时,标头中的声明使编译器可以看到/知道标识符及其类型。这样访问它们就成为可能。编译器创建的访问代码(使用占位符)然后变为可执行的,因此它始终通过填充占位符的链接器从所有代码文件中访问相同的内容。

关于重新纳入警卫的旁注。

#ifndef WIFI_TEST_H
#define WIFI_TEST_H

define 设置之前在该行中检查的宏,有效地防止再次编译相同的代码,但前提是定义已知。然而,这又仅适用于同一代码文件。
目的是避免在一个代码文件中重做相同的事情两次,如果包含此标头,则可能会发生这种情况,例如间接通过它包含的标题。 (这种特殊情况会另外创建一个循环包含...)
然而,这不会阻止头文件包含在下一个代码文件中,因为编译器不知道在其他代码文件(或包含在其他地方的头文件中)中定义的宏。它不应该阻止这一点,因为在所有访问变量的代码文件中都需要声明(而不是定义)。

【讨论】:

    猜你喜欢
    • 2021-11-28
    • 1970-01-01
    • 2013-01-09
    • 1970-01-01
    • 2014-08-04
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    • 2021-03-11
    相关资源
    最近更新 更多