C 函数调用后指针返回值更改

C 函数调用后指针返回值更改,c,pointers,return-value,C,Pointers,Return Value,来自两个C源文件的代码片段: 交流 不列颠哥伦比亚省 我编译这两个文件并创建一个静态库和一个共享库。现在我从一个示例程序调用testChannelGet。当我将它与静态库链接时,它工作得非常好。但是如果我把它和共享库联系起来,它就错了。调试告诉我,从channelGet返回的指针在返回时正在更改。下面是GDB输出 174 Channel *ch = channelGet (parser,parserCh); (gdb) s channelGet (parser=1 '\001',

来自两个C源文件的代码片段:

交流

不列颠哥伦比亚省

我编译这两个文件并创建一个静态库和一个共享库。现在我从一个示例程序调用testChannelGet。当我将它与静态库链接时,它工作得非常好。但是如果我把它和共享库联系起来,它就错了。调试告诉我,从channelGet返回的指针在返回时正在更改。下面是GDB输出

174         Channel *ch = channelGet (parser,parserCh);
(gdb) s
channelGet (parser=1 '\001', parserCh=1) at B.c:15174
15174           chnl.player = &solPlayer;
(gdb) n
15175           return((Channel *)&chnl);
(gdb) p ((Channel *)&chnl)
$1 = (Channel *) 0x7ffff7fed1a0
(gdb) n
15176   }
(gdb) n
testChannelGet at A.c:175
175         return ch;
(gdb) p ch
$2 = (Channel *) 0xfffffffff7fed1a0
地址值现在似乎指向不同的偏移量-0xfffffffff7fed1a0与0x7ffff7fed1a0。两个地址中的最后字节相同


有什么提示吗?我尝试了-fPIC选项,但没有成功。

在下面运行您的程序。查找并修复它报告的任何错误。

a.c
中的
channelGet()
范围内是否有原型

如果没有,您看到的结果可以解释如下:

  • 假定
    channelGet()
    返回
    int
    (由于缺少原型),因此结果被截断为
    0xf7fed1a0
  • 然后将其强制转换为64位指针,以便将符号扩展为
    0xfffffffff7fed1a0

(当然,如果在启用警告的情况下编译,您应该会收到投诉…

什么是
chnl
,它在哪里定义?它是在B.c-通道chnl中定义的全局变量;并在另一个文件中初始化,chnl=malloc(sizeof(Channel*));可能是在调用动态库时没有完成初始化?我认为初始化不是问题。我检查了函数中chnl的内容,它看起来不错。静态库使用相同的代码。地址更改让我很困惑。你的malloc是错误的-你正在为指针大小的东西分配空间,你需要删除星号来为通道分配空间。因为你没有分配足够的空间来获得SIGSEGV,所以你很幸运它与其他库一起工作。它在valgrind中运行得非常完美!这也让我很烦恼:(然后试着把你的问题提炼成一个完整但最小的例子,我们会有一个破解。别忘了包括你正在使用的构建过程,这可能是罪魁祸首。我确实有一个头文件中的原型,它包含在a.c和B.c中。如果问题是缺少原型,它是否适用于静态库TW当我使用静态库时,地址总是在32位范围内。当我创建共享库时,我需要任何编译器标志吗?我使用的是-gcc-fPIC-shared-Wl,-sonameYou请注意,在静态情况下,地址都在32位范围内:Linux x86_64二进制文件通常链接到以低地址0x400000运行,如果所有ad有疑问的是<0x8000000,截断后加符号扩展将没有效果。但动态库加载的地址要高得多。因此,是的,很有可能它适用于没有原型的静态库,但不适用于动态库。至于编译器标志,我想不出任何明显的东西,但是虽然看不到您是如何编译和链接每个组件的,但很难确定。嘿,这就是问题所在!我的头文件没有包括在内,因为有一些有趣的ifdef。我做了一个gcc-E,阅读了预处理器输出,但原型不在那里。修复了它,它工作得很好!非常感谢,Matthew!!
Channel *channelGet(UINT8 parser, UINT16 parserCh)
{
    chnl.player = &solPlayer;
    return((Channel *)&chnl);
}
174         Channel *ch = channelGet (parser,parserCh);
(gdb) s
channelGet (parser=1 '\001', parserCh=1) at B.c:15174
15174           chnl.player = &solPlayer;
(gdb) n
15175           return((Channel *)&chnl);
(gdb) p ((Channel *)&chnl)
$1 = (Channel *) 0x7ffff7fed1a0
(gdb) n
15176   }
(gdb) n
testChannelGet at A.c:175
175         return ch;
(gdb) p ch
$2 = (Channel *) 0xfffffffff7fed1a0