如果一个全局变量在C/C++文件中声明了两次,但不是static、extern或volatile,那么如何抛出GCC错误呢?

q5lcpyga  于 2022-11-24  发布在  C/C++
关注(0)|答案(2)|浏览(129)

did run into the situation,我在两个独立的文件中声明了两个(独立的)同名全局变量,但没有使用staticvolatileextern。一个文件是.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,直到我发现,相同的名称,两个实际上独立的变量,是造成的问题。
我的猜测是,编译器对它们使用了相同的内存区域。
我期望它作为两个独立的对象在内存中有自己的区域来处理,这显然是不正确的。
在阅读了一些问题herethere之后,我现在的理解是,如果在两个单独的C/C++文件中声明了一个同名变量,而没有声明staticexternvolatile,则该行为是未定义的。
我花了很长时间才弄明白。
如果不允许这样声明,为什么编译器/链接器没有抛出错误?
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()中的test1test_sub()覆盖,因为它在两个文件中具有相同的名称。

vvppvyoh

vvppvyoh1#

esp_mqtt_client_handle_t client;是一个试探性的定义,尽管它的名字,但它不是一个定义,只是一个声明,但如果翻译单元中没有正规的定义,它会导致在翻译单元的末尾创建一个定义。
C标准允许C实现选择如何解析多个定义(因为它说它不定义行为,所以编译器和链接器可以定义它)。在GCC版本10之前,GCC的默认设置是将临时定义中的定义标记为“common”,这意味着它们可以与其他定义合并。这导致链接器不会抱怨这样的多个定义。
-fno-common开关提供给GCC指示它不这样做;定义将不会被标记为“common”,并且如果链接器看到多个定义,它将发出警告。

slwdgvem

slwdgvem2#

你的问题真的是变量被阴影化了吗?通常对于全局变量来说,问题可能是变量没有按照正确的顺序初始化。

相关问题