0

我在静态库中有一个 C 函数,我们称它为 A,具有以下接口:

int A(unsigned int a, unsigned long long b, unsigned int *y, unsigned char *z);

这个函数将改变 y 和 z 的值(这是肯定的)。我在动态 C++ 库中使用它,使用 extern "C"。

现在,这让我感到震惊:

  • y 设置正确,z 没有改变。我的意思是,如果两者都使用(指向)值 666 进行初始化,则 y 指向的值将在调用后发生变化,但不会更改 z 指向的值(仍为 666)。
  • 当从 C 二进制文件调用时,此函数可以无缝工作(修改 z 指向的值)。
  • 如果我创建一个具有相同原型的函数的虚拟 C 库,并在我的动态 C++ 库中使用它,它工作得很好。如果我重新使用相同的变量来调用 A(..),我会得到与以前相同的结果,z 不会改变。

我认为以上几点表明我的变量声明并不是一个愚蠢的错误。

我显然被卡住了,我无法更改 C 库。您对可能是什么问题有任何线索吗?我正在考虑 C/C++ 接口上的一个问题,例如 char* 的解释方式。

编辑:我终于发现了问题所在。请看下面我的回答。

4

10 回答 10

4

看起来 C 库和 C++ 编译器处理long longs的方式有所不同。我的猜测是 C 库可能是 C89 之前的标准,实际上将 64 位长度视为 32 位长度。您的 C++ 库正在正确处理它并将 64 位放置在调用堆栈上,因此破坏了 y 和 z。也许尝试通过 *int A(unsigned int a, unsigned long b, unsigned int *y, unsigned char z)调用该函数,看看你得到了什么。

只是一个想法。

于 2008-09-29T10:00:17.983 回答
2

这是您所描述的内容没有明显错误的问题之一,但事情并没有按照您的预期进行。

我认为您应该编辑您的帖子以提供更多信息,以便获得一些明智的答案。特别是,让我们从:-

  • 此代码适用于什么平台:Windows、Linux、嵌入式或...?
  • C静态库是用什么编译器构建的?
  • C++ 动态库是用什么编译器构建的?
  • 可以成功调用构建的库的C是什么编译器?
  • 您有源代码级调试器吗?如果是这样,您能否从 C++ 单步执行 C 代码

除非您对 A 总是修改 Z 指向的数据有误,否则问题的唯一可能原因是参数传递约定之间的不兼容。“长长”的问题可能暗示事情并不像看起来那样。

作为最后的手段,你可以比较反汇编的 C++ 调用代码(你说失败)和 C 调用代码(你说成功),或者使用调试器单步执行 CPU 指令(是的,真的 - 你会学到良好的技能以及解决问题)

于 2008-09-29T12:11:17.483 回答
1

据我所知, long long 不是标准 C++ 的一部分,也许这就是你问题的根源。

于 2008-09-29T09:11:20.877 回答
1

不知道。尝试调试步骤进入 A 看看会发生什么(汇编代码警告!)

于 2008-09-29T09:14:54.240 回答
1

也许您可以将原始函数包装在您从 C++ 库中调用的 C 库中?

根据您的第 2 点和第 3 点,这似乎可行。

如果没有,它会为您提供另一个调试点以找到更多线索 - 查看故障首先出现在您的哪个库中,并检查为什么 2 和 3 工作,但这没有 - 最小的区别是什么?

您还可以尝试检查在每种情况下由您的函数调用设置的堆栈,以检查是否存在差异——考虑不同的调用约定。

于 2008-09-29T09:39:35.897 回答
1

第 1 步:比较从 C++ 端传递的指针 y 和 z 与 C 函数接收到的指针。

PS我不想听起来很明显,但只是在这里仔细检查。我想当您说从 C 二进制文件调用时 z 被修改得很好时,您的意思是 z 指向的数据被修改得很好。指针 y 和 z 本身是按值传递的,因此您不能更改指针。

于 2008-09-29T09:45:12.873 回答
1

另一个疯狂的猜测:你确定你在 C 库中链接了正确的函数实例吗?你的库中可能有几个这样的功能吗?在 C 中,链接器在决定如何解析函数时并不关心返回类型或参数列表——只有名称很重要。所以,如果你有多个同名的函数......

您可以以编程方式验证函数的身份。创建一个 C 库,它使用一些测试参数调用您的函数 A,并且工作正常并且打印指向函数 A 的指针。将该库链接到您的 C++ 应用程序。然后打印指向原始 A 函数的指针,如从 C++ 代码中看到的那样,并将指针与在同一进程中调用时 C 库看到的指针进行比较。

于 2008-09-29T12:15:56.537 回答
1

再一次,一个明显的,但谁知道......你确定你调用的 C 函数是无状态的,这意味着它的输出只取决于它的输入吗?如果函数不是无状态的,那么当从 C++ 应用程序调用时,“隐藏”状态可能会导致函数的不同行为(不更改 指向的数据z)。

于 2008-09-29T12:24:29.977 回答
1

首先,我非常感谢大家的帮助。感谢您给我的无数想法和线索,我终于能够理清这个问题。你的建议帮助我质疑我认为理所当然的事情。

对我的问题的简短回答:问题是我的 C++ 库使用了旧版本的 C 库。这个旧版本错过了第四个参数。结果,第四个论点显然从未改变过。

现在我有点惭愧,我意识到这是问题所在。但是,我的代码编译良好这一事实误导了我。这是因为 C++ 库针对正确版本的 C lib 编译,但在运行时它使用与我正在使用的另一个库静态链接的旧版本。

C++ Lib (M) ---> dyn C++ lib (N) ---> C lib (P) v.1.0
     |
     ------> C lib (P) v.1.1

(N) 是与 (P) 1.0 版静态链接的动态库。编译器接受了从 (M) 到具有 4 个参数的函数的调用,因为我链接到 (P) 版本 1.1,但在运行时它使用旧版本的 (P)。

随时编辑此答案或问题或要求我这样做。

于 2008-09-29T17:00:05.183 回答
0

在您的 C++ 程序中,原型是否用extern "C"?

于 2008-09-29T09:12:50.093 回答