4

我有一个非常令人沮丧的错误,团队中的其他人无法重现。我尝试过清理项目、擦除目录、从存储库中提取、重建,甚至在 VS 2013 中进行测试。

背景:ac、bc、cc 和 b.inc 都被编译成一个 DLL(假设它们是外部的)。setfoo()首先从托管代码中调用。到目前为止,一切都很好。

后来,testfoo()被称为。全局变量很好,没有问题。然后 testfoo2()被调用。这就是事情变得有趣的地方。我用foo's地址打开了内存调试器,它将读取 4 in memory。但是,如果您将鼠标悬停在 Visual Studio 中的代码上,它会返回 0!。此外,它将输出 0。有许多全局变量(包括FILE句柄,它们被重置为零(导致令人讨厌的 ASSERT 失败),仅在 cc 中,但在使用调试器检查时很好)。有许多其他 xc 模块包含没有问题。

好的,现在testfoo()又被调用了。公元前世界一切都很好。可怕的是,这个问题只发生在我的工作站上!关于如何调试的任何线索?

这是我的记忆,我相信代码非常接近这个骨架:

b.inc

int foo;

交流

#include <b.inc>
void setfoo(){
    foo = 4;
}

公元前

#include <b.inc>
void testfoo(){
    printf(foo); //works
}

抄送

#include <b.inc>
void testfoo2(){
    printf(foo); //foo is now 0
}

添加:这是非常复杂的遗留代码(想想 70 年代),在一家非常大的公司中,没有什么可以改变的。如果我们开始添加 extern,将会有数千个变量受到影响。另外,我在一个变量上尝试了 extern,但该文件仍然存在问题。

我遗漏了一个花絮。'testfoo2()' 在托管线程中启动。同样,这似乎与我的机器有关,可能是 Visual Studio 中的一些设置,此时不知道,我们只想重新映像盒子。

4

3 回答 3

2

您需要声明为外部:

extern int foo;

然后在一个(也是唯一一个)源文件中定义它:

int foo;

这样,一个源文件中只有一个符号,包括标题在内的所有其他源都知道链接到它。如果省略extern,则每个源文件都认为它有自己的本地私有副本foo.

那么应该定义哪个文件呢?最相关的一个。我想说a.c,因为它提供了操作的功能foo。我认为该文件是“所有者”。但是,这有点令人困惑,因为您在 中声明了它b.inc,这表明它b.c是所有者。

于 2013-09-19T23:26:20.967 回答
1

尝试这个。

b.inc

extern int foo;

交流

#include <b.inc>
int foo;

void setfoo(){
    foo = 4;
}
于 2013-09-19T23:25:06.963 回答
0

我在另一个线程中发布了这个,但我会在这里复制答案。这是一个非常微妙的错误,可以为您节省几个小时:

好的,这就是发生的事情:(以防您将来遇到这种情况)

1)在先前的构建中,有人将所有 C# Extern dll 调用拆分为两个文件。(我没有被告知)

2)他们创建了一个后期构建过程来将 dll(看看这是怎么回事)复制到另一个目录。

3)涉及的用户设置文件不在回购中,但在代码中有默认值。

4)其中一个外部 DLL 函数保留了我原来的默认值(在 filea.cs 中),但新的默认值(fileb.cs)指向构建后的位置。

据我所知,没有真正的方法可以在运行时反映 dll 的路径....

因此,当我使用 dll 副本进入函数时,当然没有全局变量,因为它是 dll 的 FRESH COPY。这是预期的行为。

内存调试器是正确的,因为另一个 dll 在内存中的某个地方保存了正确的变量。

将来我该如何防止这种情况发生?加载相同 dll 的副本时,VS 似乎被欺骗了。

于 2013-09-20T17:19:52.080 回答