简体   繁体   中英

Function returning a pointer invalidates pointer on second call

I am debugging/porting some code that I found had a curious, different behavior. What I am trying to determine is the correct behavior for the (any) compiler.

When I have a function that returns a pointer, and it is called twice, the old pointer is overwritten by the new pointer address. The issue in the sample code that I made is demonstrated by the *byte_to_binary function. If I use a single byte_to_binary function in the printf("%s\\n",byte_to_binary(x)); statement I get this result:

00100000
11110000
11011000
11001100
11000110 

If I use two byte_to_binary calls as arguments, as in

printf("%s %s\n",byte_to_binary(x),byte_to_binary(z));

you end up with the pointer representing z twice, with this output:

01100000 01100000
00110000 00110000
00011000 00011000
00001100 00001100
00000110 00000110

In many ways, this make sense to me because it seems that the compiler is just reusing the address, but from a code perspective, I would assume that the compiler would just throw two different results on the stack.

This code I present is the most succinct, repeatable explanation that I could come up with after from my original code base. The original code compiled for Solaris using Sun's CC sometime in 2006 (I no longer have access to the machine), and I am now using clang-700.1.81. The original code resulted in my expected behavior for returning the pointer to the x and then z conversion.

#include <string.h> 
#include <stdio.h>
const char *byte_to_binary(unsigned char x)
{
    static char bits[9];
    bits[0] = '\0';
    int z;
    for (z=128;z>0;z>>= 1)
    {  strcat(bits, ((x & z) == z) ? "1" : "0");  }
    return bits;
}

int main (int argc, char **argv) {


    unsigned char i;
    unsigned char x=0x80;
    unsigned char z=(3)<<5; 
    for(i=0;i<5;i++)
    {
        x=x-z;
        printf("%s %s\n",byte_to_binary(x),byte_to_binary(z));
        //printf("%s\n",byte_to_binary(x));
        z = z >> 1;
    }

}

The ultimate question is, should this line

printf("%s %s\n",byte_to_binary(x),byte_to_binary(z));

indeed return use the pointer of byte_to_binary(z) twice?

您将在第二次调用中覆盖该函数返回的地址的内容,然后printf打印两次。

When you are using the return value of byte_to_binary as a parameter to printf , the only result the compiler "throws on the stack" is the pointer value returned by byte_to_binary . Your byte_to_binary function is deliberately implemented to return the same pointer every time it is called. It returns a pointer to the same internal static buffer bits every time. In other words, each subsequent call to byte_to_binary overwrites the result of the previous call to byte_to_binary .

This immediately means that you generally cannot have more than one call to byte_to_binary in a single expression. Your printf will always print the same string twice. Which result will "win" this "competition: - byte_to_binary(x) or byte_to_binary(z) - is unspecified.

And even if you follow the convention of calling byte_to_binary no more than once in each expression, you still have to remember that the lifetime of the result pointed to by the returned pointer extends only till the next call to byte_to_binary .

Returning a pointer to a single internal static buffer is not a very viable technique in cases like that. If you really crave the convenience of not having to worry about buffer management, at least use a circular collection of static buffers. Eg something like

const char *byte_to_binary(unsigned char x)
{
    static char buffers[5][9];
    static unsigned ibuffer = 0;

    char *bits = buffers[ibuffer++];
    ibuffer %= sizeof buffers / sizeof *buffers;

    ...

    return bits;
}

This will produce expected results in your printf call. It relies on 5 buffers used in circular fashion. Of course this approach also has its drawbacks, but it is pretty viable in auxiliary code.

When you make this call:

printf("%s %s\n",byte_to_binary(x),byte_to_binary(z));

Both calls to byte_to_binary return a pointer to the same static array bits . So whichever call was executed last will dictate what bits contains.

The order in which function parameters is evaluated is undefined, so you can't depend on either one executing first.

So you can't call this function twice in one line. You need to split it up to get the results you expect:

printf("%s\n",byte_to_binary(x));
printf("%s\n",byte_to_binary(z));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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