我did run into the situation,我在两个独立的文件中声明了两个(独立的)同名全局变量,但没有使用static
、volatile
或extern
。一个文件是.c,另一个是.cpp文件。
编译器和构建环境(GCC)是ESP IDF,甚至这些声明中的数据类型也不同。
mqtt_ssl.c:
esp_mqtt_client_handle_t client;
mb_主文件.cpp:
PL::ModbusClient client(port, PL::ModbusProtocol::rtu, 1);
在运行时,我遇到了很多问题,重新启动的ESP 32,直到我发现,相同的名称,两个实际上独立的变量,是造成的问题。
我的猜测是,编译器对它们使用了相同的内存区域。
我期望它作为两个独立的对象在内存中有自己的区域来处理,这显然是不正确的。
在阅读了一些问题here和there之后,我现在的理解是,如果在两个单独的C/C++文件中声明了一个同名变量,而没有声明static
、extern
或volatile
,则该行为是未定义的。
我花了很长时间才弄明白。
如果不允许这样声明,为什么编译器/链接器没有抛出错误?
GCC是否可以选择将这种情况视为错误,以防止将来出现这种情况?
编辑1:
这是使用xtensa-esp32-elf-gcc.exe(交叉工具-NG esp-2021 r2-patch 3)8.4.0可重现的示例。
app_main.c
#include <stdio.h>
void test_sub(void);
uint16_t test1;
void app_main(void)
{
test1 = 1;
printf("app_main:test1=%d\n", test1);
test_sub();
printf("app_main:test1=%d\n", test1);
}
test_sub.c
#include <stdio.h>
int16_t test1;
void test_sub(void)
{
test1 = 2;
printf("test_sub:test1=%d\n", test1);
}
结果:
app_main:test1=1
test_sub:test1=2
app_main:test1=2
app_main()
中的test1
被test_sub()
覆盖,因为它在两个文件中具有相同的名称。
2条答案
按热度按时间vvppvyoh1#
esp_mqtt_client_handle_t client;
是一个试探性的定义,尽管它的名字,但它不是一个定义,只是一个声明,但如果翻译单元中没有正规的定义,它会导致在翻译单元的末尾创建一个定义。C标准允许C实现选择如何解析多个定义(因为它说它不定义行为,所以编译器和链接器可以定义它)。在GCC版本10之前,GCC的默认设置是将临时定义中的定义标记为“common”,这意味着它们可以与其他定义合并。这导致链接器不会抱怨这样的多个定义。
将
-fno-common
开关提供给GCC指示它不这样做;定义将不会被标记为“common”,并且如果链接器看到多个定义,它将发出警告。slwdgvem2#
你的问题真的是变量被阴影化了吗?通常对于全局变量来说,问题可能是变量没有按照正确的顺序初始化。