[英]Why does function return only one value when called multiple times in a single printf?
我遇到了一个问题,即在单个printf中多次调用返回字符串的函数时,返回错误值。 起初,我认为这是由于binstr的静态名称阻止了变量的更新。 在回顾了如何在函数中重置静态变量之后,我认为这不能解释其行为。 在创建函数时,我的目标是避免全局变量,并避免在函数内动态分配,并将free()内存的职责移交给调用例程。 首先列出了原始功能binstr_8
。 出于某种原因,我试图了解它是否在printf
多次调用,它总是返回第一次返回的值-但在所有其他情况下(在同一printf
未多次调用时)都按预期运行
/* binstr_8 - binary string for uint8_t (char) */
char *
binstr_8 (uint8_t x)
{
static char binstr [sizeof(uint8_t) * CHAR_BIT + 1] = {0};
size_t szstr = sizeof (uint8_t) * CHAR_BIT;
size_t z = 0;
for (z = 0; z < szstr; z++)
binstr [szstr - 1 - z] = ((x >> z) & 0x1) ? '1' : '0';
return binstr;
}
一个简短的示例有助于说明:
printf ("\nTesting binstr_8 & binstr_8_dyn\n\n");
be = 0b01011000; // 88
printf (" 88 & 87 = %d (%s)\n\n", (88 & 87), binstr_8 (88 & 87));
printf (" %d %s rightmost bit off: %s\n\n", be, binstr_8 (be), binstr_8 (be & (be - 1)));
printf (" 88 %s\n 87 %s\n & ---------\n %s\n\n",
binstr_8 (88), binstr_8 (87), binstr_8 (88 & 87));
您可以下载示例程序的源binstr_8_test.c从输出printf
语句是:
Testing binstr_8 & binstr_8_dyn
88 & 87 = 80 (01010000)
88 01011000 rightmost bit off: 01011000
88 01011000
87 01011000
& ---------
01011000
当所谓printf
与“最右边的位关”线的每个实例binstr_8
返回相同的值: 01011000
(这只是88,由第一次调用返回的相同binstr_8
在声明)事实上,当binstr_8
出现超过一旦进入printf
,每个调用都会返回88? (我什至对值进行了硬编码)在那里发生了什么? 分手使得每个语句printf
只包含一个调用binstr_8
工作 :
printf (" %d %s rightmost bit off: ", be, binstr_8 (be));
printf ("%s\n\n", binstr_8 (be & (be - 1)));
printf (" 88 %s\n", binstr_8 (88));
printf (" 87 %s\n", binstr_8 (87));
printf (" & ---------\n %s\n\n", binstr_8 (88 & 87));
输出:
88 01011000 rightmost bit off: 01010000
88 01011000
87 01010111
& ---------
01010000
我可以将函数binstr_8_dyn
为binstr_8_dyn
以动态分配char *binstr
,然后使用相同的printf
语句,其中包含对该函数的多次调用,并且它可以正常工作 。 那怎么可能? 例:
/* same function re-written to dynamically allocate binstr */
char *
binstr_8_dyn (uint8_t x)
{
char *binstr = NULL;
size_t z;
size_t szstr = sizeof (uint8_t) * CHAR_BIT;
binstr = (char *)malloc (szstr + 1);
binstr [szstr] = '\0';
for (z = 0; z < szstr; z++)
binstr [szstr - 1 - z] = ((x >> z) & 0x1) ? '1' : '0';
return binstr;
}
/* snip */
printf (" %d %s rightmost bit off: %s\n\n", be, binstr_8_dyn (be), binstr_8_dyn (be & (be - 1)));
printf (" 88 %s\n 87 %s\n & ---------\n %s\n\n",
binstr_8_dyn (88), binstr_8_dyn (87), binstr_8_dyn (88 & 87));
输出正确:
88 01011000 rightmost bit off: 01010000
88 01011000
87 01010111
& ---------
01010000
现在,我已成功地完全迷惑自己,为什么binstr_8
不能在同一个被多次调用printf
同时binstr_8_dyn
即可。 我忽略了什么基本原则? 另外,除了使用静态或动态分配外,我还应该如何提供返回而不涉及全局或传递指针?
当返回static
变量的地址并再次使用时,该值始终是相同的,并且它是最后一个已计算的值。
binstr_8
函数每次都返回相同的指针-指向静态缓冲区的指针。
因此,如果将它两次作为参数传递给printf,则printf将两次接收相同的缓冲区,因此同一事物将打印两次。 对binstr_8
两次调用都在调用printf
之前运行(显然,必须在调用函数之前对函数的参数求值)。
每次malloc
示例都会返回一个不同的缓冲区。
更新 :在binstr_8
函数内部使用多个静态缓冲区的binstr_8
:
static char binstr [5][CHAR_BIT + 1];
static char which = 0;
if ( ++which == 5 ) which = 0;
// use binstr[which] where you had binstr
然后,在每个printf
您最多可以使用五个对binstr_8
调用。
您将返回一个指向静态缓冲区的指针,因此所有binstr都指向相同的内存位置。 创建新的二进制文件时,您将覆盖所有现有的二进制文件。 对于binstr_dyn,它们是不同的缓冲区。 由于在函数调用之前对所有参数进行了求值,因此printf会打印最后创建的字符串的值,该值恰好是88,因为对参数求值的顺序未定义。
binstr_8_dyn是正确的填充,但是您将需要重新尝试释放它创建的每个字符串。
添加到Matt McNabb的答案中:
对于这样的函数,可以预先确定输出字符串的长度,因此可以使调用方分配输出缓冲区。 缓冲区可以是自动的,可以避免释放问题:
#define STR8LEN (sizeof (uint8_t) * CHAR_BIT)
#define STR8BUFLEN (sizeof (uint8_t) * CHAR_BIT + 1)
char *binstr_8 (uint8_t x, char *binstr)
{
size_t z;
size_t szstr = STR8LEN;
binstr [szstr] = 0;
for (z = 0; z < szstr; x >>= 1, z++)
binstr [szstr - 1 - z] = '0' + (x & 1);
return binstr;
}
void fun()
{
char buf1 [STR8BUFLEN], buf2 [STR8BUFLEN], buf3 [STR8BUFLEN];
printf (" 88 %s\n 87 %s\n & ---------\n %s\n\n",
binstr_8 (88, buf1), binstr_8 (87, buf2),
binstr_8 (88 & 87, buf3));
}
调用者函数fun()
职责是在调用之前分配缓冲区,并在使用后释放它们; binstr_8
只是使用它们。 每次使用单独的缓冲区调用binstr_8
,结果不会重叠,并且每次调用都返回自己的缓冲区,因此printf可以使用它们。 您还可以稍后使用它们,因为它们会保留它们的内容,只要它们存在(只要您不覆盖它们!):
void fun()
{
char buf1 [STR8BUFLEN], buf2 [STR8BUFLEN], buf3 [STR8BUFLEN];
binstr_8 (88, buf1);
binstr_8 (87, buf2);
binstr_8 (88 & 87, buf3);
printf (" 88 %s\n 87 %s\n & ---------\n %s\n\n",
buf1, buf2, buf3);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.