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

Function returning a pointer invalidates pointer on second call

我 debugging/porting 我发现一些代码有奇怪的不同行为。我要确定的是(任何​​)编译器的正确行为。

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

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。原始代码导致了我对 return 指向 x 然后 z 转换的指针的预期行为。

#include <string.h> 
#include <stdio.h>
const char *byte_to_binary(unsigned char x)
{
    static char bits[9];
    bits[0] = '[=13=]';
    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));

确实return使用了两次byte_to_binary(z)的指针?

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

当您拨打此电话时:

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

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

未定义计算函数参数的顺序,因此您不能依赖其中任何一个先执行。

所以你不能在一行中调用这个函数两次。您需要将其拆分以获得您期望的结果:

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

当您使用 byte_to_binary 的 return 值作为 printf 的参数时,编译器 "throws on the stack" 的唯一结果是 指针 值 return 由 byte_to_binary 编辑。你的 byte_to_binary 函数在每次调用时都被故意实现为 return 相同的 指针。它 return 每次都是指向 相同 内部静态缓冲区 bits 的指针。换句话说,每次后续调用 byte_to_binary 都会覆盖 先前调用 byte_to_binary.

的结果

这立即意味着您通常不能在单个表达式中多次调用 byte_to_binary。您的 printf 将始终打印相同的字符串两次。 "win" 这场“比赛的结果是:- byte_to_binary(x)byte_to_binary(z) - 未指定。

并且即使您遵循在每个表达式中调用 byte_to_binary 不超过一次的惯例,您仍然必须记住 returned 指针指向的结果的生命周期会延长直到下一次调用 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;
}

这将在您的 printf 调用中产生预期的结果。它依赖于以循环方式使用的 5 个缓冲区。当然这种方式也有不足之处,但是在辅助代码中还是很可行的。