简体   繁体   English

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

[英]Why does function return only one value when called multiple times in a single printf?

I ran across an issue where a function that returns a character string returns incorrect values when called multiple times within a single printf . 我遇到了一个问题,即在单个printf中多次调用返回字符串的函数时,返回错误值。 At first I thought it was due to the static designation of binstr preventing the variable from updating. 起初,我认为这是由于binstr的静态名称阻止了变量的更新。 After reviewing How to reset static variables within a function I don't think that explains the behavior. 在回顾了如何在函数中重置静态变量之后,我认为这不能解释其行为。 In creating the function, my goal was to avoid global variables and to avoid dynamically allocating within the function and turning over the responsibility to free() the memory to the calling routine. 在创建函数时,我的目标是避免全局变量,并避免在函数内动态分配,并将free()内存的职责移交给调用例程。 Below the original function binstr_8 is listed first. 首先列出了原始功能binstr_8 For reasons I'm trying to understand if it is called multiple times within printf it always returns the value of the first return - but behaves as desired in all other situations (when not called multiple times in the same printf ) 出于某种原因,我试图了解它是否在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;
}

A short example helps explain: 一个简短的示例有助于说明:

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));

You can download the source of the example program binstr_8_test.c The output from the printf statements are: 您可以下载示例程序的源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

When called in the printf line with "rightmost bit off", each instance of binstr_8 returns the same value: 01011000 (which is just 88, the same returned by the first call of binstr_8 in the statement) In fact, when binstr_8 appears more than once in a printf , every call returns 88? 当所谓printf与“最右边的位关”线的每个实例binstr_8返回相同的值: 01011000 (这只是88,由第一次调用返回的相同binstr_8在声明)事实上,当binstr_8出现超过一旦进入printf ,每个调用都会返回88? (I even hardcoded the values) What is going on there? (我什至对值进行了硬编码)在那里发生了什么? Breaking the statements up such that each printf contains only a single call to binstr_8 works : 分手使得每个语句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));    

Output: 输出:

88  01011000  rightmost bit off: 01010000

88  01011000
87  01010111
&  ---------
    01010000

I can re-write the function as binstr_8_dyn to dynamically allocate char *binstr and then use the same printf statements containing multiple calls to the function and it works . 我可以将函数binstr_8_dynbinstr_8_dyn以动态分配char *binstr ,然后使用相同的printf语句,其中包含对该函数的多次调用,并且它可以正常工作 How is that possible? 那怎么可能? Example: 例:

/* 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));

The output is correct: 输出正确:

88  01011000  rightmost bit off: 01010000

88  01011000
87  01010111
&  ---------
    01010000

Now I have managed to totally confuse myself as to why binstr_8 cannot be called multiple times in the same printf while binstr_8_dyn can. 现在,我已成功地完全迷惑自己,为什么binstr_8不能在同一个被多次调用printf同时binstr_8_dyn即可。 What fundamental principle am I overlooking? 我忽略了什么基本原则? Also, how else would I provide the return without involving a global or passing a pointer other than using static or allocating dynamically? 另外,除了使用静态或动态分配外,我还应该如何提供返回而不涉及全局或传递指针?

当返回static变量的地址并再次使用时,该值始终是相同的,并且它是最后一个已计算的值。

The binstr_8 function returns the same pointer every time - a pointer to your static buffer. binstr_8函数每次都返回相同的指针-指向静态缓冲区的指针。

So if you pass it twice as argument to printf, printf receives the same buffer twice, therefore the same thing prints twice. 因此,如果将它两次作为参数传递给printf,则printf将两次接收相同的缓冲区,因此同一事物将打印两次。 Both calls to binstr_8 run before printf is called (a function's arguments must be evaluated before the function is called, obviously). binstr_8两次调用都在调用printf之前运行(显然,必须在调用函数之前对函数的参数求值)。

The malloc example returns a different buffer each time. 每次malloc示例都会返回一个不同的缓冲区。

Update : example of using multiple static buffers, inside the binstr_8 function: 更新 :在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

Then you can use up to five calls to binstr_8 in each printf . 然后,在每个printf您最多可以使用五个对binstr_8调用。

You are returning a pointer to the static buffer so all of the binstrs point to the same memory location. 您将返回一个指向静态缓冲区的指针,因此所有binstr都指向相同的内存位置。 When you create a new one you are overwriting all of the existing binstrs. 创建新的二进制文件时,您将覆盖所有现有的二进制文件。 With binstr_dyn they are are different buffers. 对于binstr_dyn,它们是不同的缓冲区。 As all of your arguments are evaluated before the function call the printf prints the values of the last string created, which happens to be 88 because to order of evaluation of arguments is undefined. 由于在函数调用之前对所有参数进行了求值,因此printf会打印最后创建的字符串的值,该值恰好是88,因为对参数求值的顺序未定义。

binstr_8_dyn is the correct inplementation but you will neet to rember to free every string it creates. binstr_8_dyn是正确的填充,但是您将需要重新尝试释放它创建的每个字符串。

Adding to Matt McNabb's answer: 添加到Matt McNabb的答案中:

For a function like that the output string length can be determined in advance, so you can make a caller to allocate the output buffer. 对于这样的函数,可以预先确定输出字符串的长度,因此可以使调用方分配输出缓冲区。 Buffers can be automatic and you avoid problems with deallocation: 缓冲区可以是自动的,可以避免释放问题:

#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));
}

It's a caller function fun() responsibility to allocate buffers prior to call and free them after use; 调用者函数fun()职责是在调用之前分配缓冲区,并在使用后释放它们; binstr_8 just uses them. binstr_8只是使用它们。 Each time binstr_8 is called with a separate buffer, so the results do not overlap, and each call returns its own buffer as a result, so they can be used by printf. 每次使用单独的缓冲区调用binstr_8 ,结果不会重叠,并且每次调用都返回自己的缓冲区,因此printf可以使用它们。 You can also use them later, as they keep their contents as long as they exist (provided you do not overwrite them!): 您还可以稍后使用它们,因为它们会保留它们的内容,只要它们存在(只要您不覆盖它们!):

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