为什么通过引用传递的参数未在函数中修改?

时间:2020-03-06 14:52:01  来源:igfitidea点击:

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

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

此函数将更改y和z的值(这是肯定的)。我在动态C ++库中使用外部" C"来使用它。

现在,这就是让我震惊的地方:

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

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

我显然被卡住了,无法更改C库。我们有什么问题的线索吗?
我一直在思考C / C ++接口上的问题,例如,每个char *的解释方式。

编辑:我终于发现了问题所在。见下面我的答案。

解决方案

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

在C ++程序中,原型是否用extern" C"声明?

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

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

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

如果没有,它将为我们提供另一个调试点,以找到更多线索,以查看首先出现故障的库中的哪一个,并检查2和3为何起作用,但这不是最小的区别吗?

我们还可以尝试检查每种情况下函数调用所建立的堆栈,以检查差异是否在这里-考虑不同的调用约定。

步骤1:将C ++端传递的指针y和z与C函数接收的指针进行比较。

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

C库和C ++编译器处理长整型的方式似乎有所不同。我的猜测是C库可能是C89标准之前的版本,实际上将64位长视为32位长。C ++库正在正确处理它,并将64位放置在调用堆栈上,从而损坏了y和z。也许尝试通过* int A(unsigned int a,unsigned long b,unsigned int * y,unsigned char z)调用函数,然后看看得到了什么。

只是一个想法。

这是那些问题,其中我们所描述的内容显然没有错,但是事情并没有按照预期进行。

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

  • 该代码用于什么平台:Windows,Linux,嵌入式或者...?
  • C静态库使用什么编译器?
  • C ++动态库使用什么编译器构建?
  • 可以成功调用使用其构建的库的C语言是什么编译器?
  • 我们是否有源代码级调试器?如果是这样,我们可以从C ++进入C代码吗?

除非我们对A总是修改Z所指向的数据有误,否则造成问题的唯一可能原因是参数传递约定之间不兼容。 "长期长期"问题可能暗示着事情似乎并不像看起来那样。

作为最后的选择,我们可以将反汇编的C ++调用代码(我们说失败)和C调用代码(我们说成功)进行比较,或者通过调试器逐步执行CPU指令(是的,确实可以学到很多东西)。技巧以及解决问题的能力)

另一个疯狂的猜测:我们确定要链接到C库中该函数的正确实例吗?库中是否有几个可用的此类功能?在C语言中,链接器在决定如何解析函数时并不关心返回类型或者参数列表-仅名称很重要。因此,如果我们有多个具有相同名称的功能...

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

同样,这是一个显而易见的例子,但是谁知道...我们确定要调用的C函数是无状态的,这意味着其输出仅取决于其输入吗?如果该函数不是无状态的,则可能是从C ++应用程序调用时,该"隐藏"状态负责该函数的不同行为(不更改" z"所指向的数据)。

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

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

现在,我意识到这是问题,对此我感到ham愧。但是,我的代码可以很好地编译,这使我误入歧途。这是由于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)的旧版本。

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