繁体   English   中英

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

[英]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_dynbinstr_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM