函数调用后指针返回值发生变化

Vas*_*asu 5 c pointers return-value

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

AC

Channel *testChannelGet()
{
    Channel *ch = channelGet (parser,parserCh);
    return ch;
}
Run Code Online (Sandbox Code Playgroud)

公元前

Channel *channelGet(UINT8 parser, UINT16 parserCh)
{
    chnl.player = &solPlayer;
    return((Channel *)&chnl);
}
Run Code Online (Sandbox Code Playgroud)

我编译这两个文件并创建一个静态库和一个共享库.现在我从示例程序中调用testChannelGet.当我将它链接到静态库时,它完美地工作.但是,如果我将它链接到共享库,它的SEGFAULTing.调试告诉我,从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
Run Code Online (Sandbox Code Playgroud)

现在地址值似乎指向不同的偏移量 - 0xfffffffff7fed1a0 vs 0x7ffff7fed1a0.两个地址中的最后一个字节是相同的.

任何提示?我试过-fPIC选项无济于事.

Mat*_*ery 6

是否有范围原型channelGet()A.c

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

  • channelGet()假设返回int(由于缺少原型),因此结果被截断为0xf7fed1a0
  • 然后它被转换为64位指针,因此进行符号扩展 0xfffffffff7fed1a0

(如果编译时启用警告,你应该得到关于这个的投诉,当然......)

  • 您会注意到,在静态情况下,地址都在32位范围内:Linux x86_64二进制文件通常被链接为在低地址0x400000上运行,并且如果所有有问题的地址均<0x80000000,则截断后跟一个符号扩展名将无效。但是动态库会加载到更高的地址。因此,是的,完全可以想象它可以在没有原型的情况下用于静态库,但不能用于动态库。至于编译器标志,我想不出什么明显的方法,但是如果看不到如何编译和链接每个组件,就很难确定。 (2认同)