简体   繁体   English

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

[英]Why is my parameter passed by reference not modified within the function?

I have got a C function in a static library, let's call it A, with the following interface : 我在静态库中有一个C函数,我们将其称为A,具有以下接口:

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

This function will change the value of y an z (this is for sure). 此函数将更改y和z的值(这是肯定的)。 I use it from within a dynamic C++ library, using extern "C". 我在动态C ++库中使用外部“ C”来使用它。

Now, here is what stune me : 现在,这就是让我震惊的地方:

  • y is properly set, z is not changed. y设置正确,z不变。 What I exactly mean is that if both are initialized with a (pointed) value of 666, the value pointed by y will have changed after the call but not the value pointed by z (still 666). 我的意思是,如果都使用666的(指向的)值进行初始化,则在调用之后,由y指向的值将已更改,但由z指向的值将保持不变(仍为666)。
  • when called from a C binary, this function works seamlessly (value pointed by z is modified). 当从C二进制文件调用时,此函数无缝运行(z指向的值已修改)。
  • if I create a dummy C library with a function having the same prototype, and I use it from within my dynamic C++ library, it works very well. 如果我创建一个具有相同原型函数的虚拟C库,并且在动态C ++库中使用它,那么它会很好地工作。 If I re-use the same variables to call A(..), I get the same result as before, z is not changed. 如果我重复使用相同的变量来调用A(..),则得到的结果与以前相同,z不变。

I think that the above points show that it is not a stupid mistake with the declaration of my variables. 我认为以上几点表明,声明变量不是愚蠢的错误。

I am clearly stuck, and I can't change the C library. 我显然被卡住了,无法更改C库。 Do you have any clue on what can be the problem ? 您有什么问题的线索吗? I was thinking about a problem on the C/C++ interface, per instance the way a char* is interpreted. 我一直在思考C / C ++接口上的问题,例如,每个char *的解释方式。

Edit : I finally found out what was the problem. 编辑:我终于发现了问题所在。 See below my answer. 见下面我的答案。

It looks like a difference between the the way your C library and C++ compiler is dealing with long longs . 您的C库和C ++编译器处理long long的方式似乎有所不同。 My guess is that it is that the C library is probably pre C89 standard and actually treating the 64bit long long as a 32bit long. 我的猜测是C库可能是C89标准之前的版本,实际上将64位视为32位长。 Your C++ library is handling it correctly and placing 64bits on the call stack and hence corrupting y and z. 您的C ++库正在正确处理它,并将64位放置在调用堆栈上,从而损坏了y和z。 Maybe try calling the function through *int A(unsigned int a, unsigned long b, unsigned int *y, unsigned char z) , and see what you get. 也许尝试通过* int A(unsigned int a,unsigned long b,unsigned int * y,unsigned char z)调用函数,然后看看会得到什么。

Just a thought. 只是一个想法。

This is one of those questions where there's nothing obviously wrong from what you've described, yet things aren't working the way you expect. 这是那些问题,其中您所描述的内容显然没有错,但是事情并没有按照您的预期进行。

I think you should edit your post to give a lot more information in order to get some sensible answers. 我认为您应该编辑您的帖子以提供更多信息,以获得一些明智的答案。 In particular, let's start with:- 特别地,让我们开始:

  • What platform is this code for: Windows, linux, something embedded or ...? 该代码用于什么平台:Windows,Linux,嵌入式或...?
  • What compiler is the C static library built with? C静态库使用什么编译器?
  • What compiler is the C++ dynamic library built with? C ++动态库使用什么编译器构建?
  • What compiler is the C which can successfully call the library built with? 可以成功调用使用其构建的库的C语言是什么编译器?
  • Do you have a source-level debugger? 您是否有源代码级调试器? If so, can you step into the C code from the C++. 如果是这样,您可以从C ++ 进入 C代码。

Unless you're wrong about A always modifying the data pointed to by Z, the only likely cause of your problem is an incompatibility between the parameter passing conventions . 除非您对A总是在修改Z所指向的数据有错,否则,您出现问题的唯一可能原因是参数传递约定之间不兼容。 The "long long" issue may be a hint that things are not as they seem. “长期长期”问题可能暗示着事情并非看起来那样。

As a last resort, you could compare the disassembled C++ calling code (which you say fails) and the C calling code (which you say succeeds), or step through the CPU instructions with the debugger (yes, really - you'll learn a good skill as well as solving the problem) 作为最后的选择,您可以将反汇编的C ++调用代码(您说失败)和C调用代码(您说成功)进行比较,或者通过调试器逐步执行CPU指令(是的,实际上-您将学到一个技巧和解决问题的能力)

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

dunno. 不知道。 Try to debug-step into A and see what happens (assembly code alert!) 尝试调试进入A的步骤,看看会发生什么(汇编代码警报!)

Maybe you can wrap the original function in a C library that you call from your C++ library? 也许您可以将原始函数包装在从C ++库调用的C库中?

Based on your points 2 and 3, it seems like this could work. 根据您的第2点和第3点,这似乎可行。

If it doesn't, it gives you another debug point to find more clues - see which of your libraries the failure first pops up in, and check why 2 and 3 work, but this doesn't - what is the minimal difference? 如果不行,它将为您提供另一个调试点,以查找更多线索-查看首先出现故障的库中的哪个,并检查2和3为何起作用,但这不行-最小的区别是什么?

You could also try to examine the stack that is set up by your function call in each case to check if the difference is here -- considering different calling conventions. 您还可以尝试检查每种情况下由函数调用建立的堆栈,以检查差异是否在这里-考虑不同的调用约定。

Step 1: Compare the pointers y and z passed from the C++ side with those received by the C function. 步骤1:将C ++端传递的指针y和z与C函数接收的指针进行比较。

PS I don't want to sound obvious, but just double-checking here. PS:我不想听起来很明显,但在这里请仔细检查。 I suppose when you say that z is modified just fine when called from a C binary, you mean that the data where z is pointing is modified just fine. 我想,当您说从C二进制文件中调用z时,它被修改得很好,您的意思是z指向的数据被修改了。 The pointers y and z themselves are passed by value, so you can't change the pointers. 指针y和z本身按值传递,因此您不能更改指针。

Another wild guess: are you sure you're linking against the right instance of the function in your C library? 另一个疯狂的猜测:您确定要链接到C库中函数的正确实例吗? Could it be that there are several such functions available in your libraries? 您的库中是否有几个可用的此类功能? In C the linker doesn't care about the return type or the parameter list when deciding how to resolve a function -- only the name is important. 在C语言中,链接器在决定如何解析函数时并不关心返回类型或参数列表-仅名称很重要。 So, if you have multiple functions with the same name... 因此,如果您有多个具有相同名称的功能...

You could programmatically verify the identity of the function. 您可以以编程方式验证功能的身份。 Create a C library that calls your function A with some test parameters and that works fine and that prints the pointer to function A. Link the library into your C++ app. 创建一个C库,该C库使用一些测试参数调用您的函数A,并且可以正常工作,并输出指向函数A的指针。将该库链接到您的C ++应用程序中。 Then print the pointer to the original A function as seen from the C++ code and compare the pointer with that seen by your C library when invoked in the same process. 然后从C ++代码中看到指向原始A函数的指针,并将该指针与在同一过程中调用时C库所看到的指针进行比较。

Again, an obvious one, but who knows... Are you sure the C function you're invoking is stateless, meaning its output depends only on its inputs? 再说一次,很明显,但是谁知道...您确定要调用的C函数是无状态的,这意味着其输出仅取决于其输入吗? If the function isn't stateless, then it might be that the "hidden" state is responsible for the different behavior (not changing the data pointed to by z ) of the function when invoked from your C++ app. 如果该函数不是无状态的,则可能是从C ++应用程序调用时,该“隐藏”状态负责该函数的不同行为(不更改z指向的数据)。

First of all, I am very grateful to everyone for your help. 首先,我非常感谢大家的帮助。 Thanks to the numerous ideas and clues you gave me, I have been able to finally sort out this problem. 感谢您提供给我的无数想法和线索,我终于能够解决这个问题。 Your advices helped me to question what I took for granted. 您的建议帮助我质疑我认为是理所当然的事情。

Short answer to my problem : The problem was that my C++ library used an old version of the C library. 我的问题的简短答案:问题是我的C ++库使用了旧版本的C库。 This old version missed the 4th argument. 这个旧版本错过了第四个论点。 As a consequence, the 4th argument was obviously never changed. 结果,第四个论点显然没有改变。

I am a bit ashamed now that I realised this was the problem. 现在,我意识到这是问题,对此我感到ham愧。 However, I was misslead by the fact that my code was compiling fine. 但是,我的代码可以很好地编译,这使我误入歧途。 This was due to the fact that the C++ library compiled against the correct version of the C lib, but at runtime it used the old version statically linked with another library that I was using. 这是由于C ++库针对正确版本的C lib进行编译,但是在运行时它使用的旧版本与我正在使用的另一个库静态链接。

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

(N) is a dynamic library which is statically linked with (P) version 1.0. (N)是一个动态库,它与(P)1.0版静态链接。 The compiler accepted the call from (M) to the function with 4 arguments because I linked against (P) version 1.1, but at runtime it used the old version of (P). 编译器接受了从(M)对带有4个参数的函数的调用,因为我链接了(P)1.1版,但在运行时它使用的是(P)的旧版本。

Feel free to edit this answer or the question or to ask me to do so. 随时编辑此答案或问题,或要求我这样做。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么 cppcheck 说“函数参数应该通过引用传递”? - why cppcheck say “Function parameter should be passed by reference”? 如果参数被传递两次,会发生什么情况? 一次按值,一次按引用? 会修改还是不修改? - What happens to a parameter if it is passed twice? Once by value and once by reference? Will it be modified or not? 在函数C ++中由引用传递的指针参数 - pointer parameter passed by reference in a function c++ 为什么适配器兼容的 function object 不能作为参考传递参数? - Why adaptor-compatible function object can't be passed parameter as reference? 为什么不能将作为常量引用传递给 function 的数组的 .size() 用作模板参数? - Why can't the .size() of an array passed to a function as a constant reference be used as a template parameter? 为什么成员变量没有传递给修改过的函数? - Why isn't the member variable passed to a function modified? 为什么这不能作为成员函数中的默认参数传递? - Why this can not be passed as default parameter in member function? 为什么在函数参数中将字符串作为 const 字符串传递 - Why is a string passed as const string in a function parameter 在函数内部使用通过引用传递给函数的参数的地址有什么害处吗? - Is there any harm in using the address of a parameter passed by reference to a function, inside the function? 为什么不调用在构造函数中作为参数传递的自由函数? - Why a free function passed as a parameter in the constructor is not called?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM