ESP32变量的多重定义

Multiple definition of variables ESP32

我正在为我的 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 以确保没有留下任何旧的东西,仍然没有运气。

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

(接受并扩展一些程序员的评论,将这个问题从未回答的问题列表中删除。我相信他不介意,但建议删除其他内容。)

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

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

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

改为在 header 文件中声明变量(使用 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;

独特的代码文件部分使单一定义成为可能,没有倍数,让链接器满意。
同时,在编译所有其他代码文件时,header 中的声明将标识符及其类型 visible/known 提供给编译器。这样就可以访问它们。由编译器(使用占位符)创建的访问代码随后变为可执行文件,因此它总是通过填充占位符的链接器访问所有代码文件中的相同内容。

关于重新收容守卫的旁注。

#ifndef WIFI_TEST_H
#define WIFI_TEST_H

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