返回指针的函数在第二次调用时使指针无效
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 个缓冲区。当然这种方式也有不足之处,但是在辅助代码中还是很可行的。
我 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 个缓冲区。当然这种方式也有不足之处,但是在辅助代码中还是很可行的。