返回指针的函数使第二次调用时的指针无效

时间:2016-02-09 18:58:41

标签: c pointers clang

我正在调试/移植一些代码,我发现这些代码有一种奇怪的,不同的行为。我想确定的是(任何​​)编译器的正确行为。

当我有一个返回指针的函数,并且它被调用两次时,新指针地址会覆盖旧指针。我所做的示例代码中的问题由* byte_to_binary函数演示。如果我在byte_to_binary语句中使用单个printf("%s\n",byte_to_binary(x));函数,我会得到以下结果:

00100000
11110000
11011000
11001100
11000110 

如果我使用两个byte_to_binary调用作为参数,如

printf("%s %s\n",byte_to_binary(x),byte_to_binary(z));

你最终得到了两次表示z的指针,输出结果为:

01100000 01100000
00110000 00110000
00011000 00011000
00001100 00001100
00000110 00000110

在很多方面,这对我来说很有意义,因为看起来编译器只是在重用地址,但从代码的角度来看,我认为编译器会在堆栈上抛出两个不同的结果。

我提供的这段代码是我在原始代码库之后可以提出的最简洁,可重复的解释。在2006年的某个时候使用Sun的CC编译的Solaris原始代码(我不再能访问该机器),现在我使用的是clang-700.1.81。原始代码导致我将指针返回到x然后z转换的预期行为。

#include <string.h> 
#include <stdio.h>
const char *byte_to_binary(unsigned char x)
{
    static char bits[9];
    bits[0] = '\0';
    int z;
    for (z=128;z>0;z>>= 1)
    {  strcat(bits, ((x & z) == z) ? "1" : "0");  }
    return bits;
}

int main (int argc, char **argv) {


    unsigned char i;
    unsigned char x=0x80;
    unsigned char z=(3)<<5; 
    for(i=0;i<5;i++)
    {
        x=x-z;
        printf("%s %s\n",byte_to_binary(x),byte_to_binary(z));
        //printf("%s\n",byte_to_binary(x));
        z = z >> 1;
    }

}

最终的问题是,这一行

printf("%s %s\n",byte_to_binary(x),byte_to_binary(z));

确实返回使用byte_to_binary(z)的指针两次?

3 个答案:

答案 0 :(得分:1)

您正在覆盖该函数返回的地址内容,在第二次调用中,然后printf打印两次。

答案 1 :(得分:1)

当您使用byte_to_binary的返回值作为printf的参数时,编译器“抛出堆栈”的唯一结果是返回的指针byte_to_binary。故意实现byte_to_binary函数,以便在每次调用时返回相同的指针。它每次都返回一个指向相同内部静态缓冲区bits的指针。换句话说,对byte_to_binary 的每次后续调用都会覆盖上次调用byte_to_binary的结果。

这意味着您通常不能在单个表达式中对byte_to_binary进行多次调用。您的printf将始终打印两次相同的字符串。哪个结果将“赢得”此竞赛: - byte_to_binary(x)byte_to_binary(z) - 未指定。

即使您遵循在每个表达式中调用byte_to_binary的约定不超过一次,您仍然必须记住返回指针指向的结果的生命周期仅延伸到下一次调用{ {1}}。

在这种情况下,返回指向单个内部静态缓冲区的指针并不是一种非常可行的技术。如果你真的渴望不必担心缓冲区管理,至少使用循环的静态缓冲区集合。例如。

之类的东西
byte_to_binary

这会在const char *byte_to_binary(unsigned char x) { static char buffers[5][9]; static unsigned ibuffer = 0; char *bits = buffers[ibuffer++]; ibuffer %= sizeof buffers / sizeof *buffers; ... return bits; } 来电中产生预期结果。它依赖于循环使用的5个缓冲区。当然这种方法也有其缺点,但它在辅助代码中非常可行。

答案 2 :(得分:-1)

当您拨打此电话时:

printf("%s %s\n",byte_to_binary(x),byte_to_binary(z));

byte_to_binary的两次调用都返回指向同一静态数组bits的指针。因此,最后执行的调用将决定bits包含的内容。

评估函数参数的顺序是未定义的,因此您不能依赖于首先执行的任何一个。

因此,您无法在一行中调用此功能两次。您需要将其拆分以获得预期的结果:

printf("%s\n",byte_to_binary(x));
printf("%s\n",byte_to_binary(z));