Search code examples
carraysstructreturn-valuelvalue

printing a member of a returned struct


I'm having trouble printing a member of a struct that is returned from a function:

#include <stdio.h>

struct hex_string
{
    char a[9];
};

struct hex_string to_hex_string_(unsigned x)
{
    static const char hex_digits[] = "0123456789ABCDEF";
    struct hex_string result;
    char * p = result.a;
    int i;
    for (i = 28; i >= 0; i -= 4)
    {
        *p++ = hex_digits[(x >> i) & 15];
    }
    *p = 0;
    printf("%s\n", result.a);   /* works */
    return result;
}

void test_hex(void)
{
    printf("%s\n", to_hex_string_(12345).a);   /* crashes */
}

The printf call inside to_hex_string_ prints the correct result, but the printf call inside test_hex crashes my program. Why exactly is that? Is it a lifetime issue, or is it something else?

When I replace the printf call with puts(to_hex_string_(12345).a), I get a compiler error:

invalid use of non-lvalue array

What's going on here?


Solution

  • There is a rule in C which seldom comes into effect, which states:

    If an attempt is made to modify the result of a function call or to access it after the next sequence point, the behavior is undefined. (C99 §6.5.2.2)

    In this case, there is a sequence point after the arguments to printf() are evaluated and before the printf() function itself executes. The pointer you pass to printf() is a pointer to an element of the return value itself - and when printf() tries to access the string through that pointer, you get your crash.

    This issue is hard to run into, because a function value isn't an lvalue so you can't directly take a pointer to it with &.