为什么函数在单个printf中多次调用时只返回一个值?

时间:2014-06-03 23:09:12

标签: c function printf

我遇到了一个问题,即在单个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_8binstr_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}}。我忽略了什么基本原则?另外,除了使用静态或动态分配之外,我还会如何提供返回而不涉及全局或传递指针?

4 个答案:

答案 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);
}