我遇到了一个问题,即在单个printf中多次调用时,返回字符串的函数返回的值不正确。起初我认为这是由于binstr的静态指定阻止变量更新。在审核How to reset static variables within a function之后,我不认为这可以解释这种行为。在创建函数时,我的目标是避免全局变量并避免在函数内动态分配并将责任转交给free()将内存释放到调用例程。首先列出原始函数binstr_8
下方。由于我试图理解它是否在printf
内被多次调用它总是返回第一次返回的值 - 但在所有其他情况下表现得如此(在同一时间内未被多次调用时) {1}})
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;
}
您可以下载示例程序的来源binstr_8_test.c 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));
语句的输出是:
printf
在Testing binstr_8 & binstr_8_dyn
88 & 87 = 80 (01010000)
88 01011000 rightmost bit off: 01011000
88 01011000
87 01011000
& ---------
01011000
行中调用&#34;最右边的位&#34;, printf
的每个实例返回相同的值:binstr_8
(这只是88,声明中01011000
的第一次调用返回的内容相同事实上,当binstr_8
在binstr_8
中多次出现时,每次调用都会返回88? (我甚至硬编码了这些值)那里发生了什么?
打破陈述,使每个printf
仅包含对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
,然后使用包含对函数的多次调用的相同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
期间无法多次调用{{1}}。我忽略了什么基本原则?另外,除了使用静态或动态分配之外,我还会如何提供返回而不涉及全局或传递指针?
答案 0 :(得分:4)
当您返回重复使用并再次重用的static
变量的地址时,该值始终相同,并且它是已计算的最后一个。
答案 1 :(得分:4)
binstr_8
函数每次都返回相同的指针 - 一个指向静态缓冲区的指针。
因此,如果将它作为参数传递给printf两次,则printf会接收两次相同的缓冲区,因此同样的事情会打印两次。调用binstr_8
之前调用printf
的两个调用(函数的参数必须在调用函数之前进行计算)。
malloc
示例每次都返回一个不同的缓冲区。
更新:在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
然后,您可以在每个binstr_8
中最多使用五次printf
次来电。
答案 2 :(得分:1)
您正在返回指向静态缓冲区的指针,因此所有binstrs都指向相同的内存位置。当您创建一个新的时,您将覆盖所有现有的二进制文件。使用binstr_dyn,它们是不同的缓冲区。由于所有参数都是在函数调用之前计算的,因此printf会打印出最后创建的字符串的值,这恰好是88,因为参数的评估顺序是未定义的。
binstr_8_dyn是正确的inplementation,但你需要rember来释放它创建的每个字符串。
答案 3 :(得分:0)
添加到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);
}