printing a member of a returned struct

走远了吗. 提交于 2019-11-29 06:19:44

问题


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?


回答1:


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 &.




回答2:


You've managed to run into a fairly obscure corner case of the language.

An expression of array type, in most contexts, is implicitly converted to a pointer to the first element of the array; the exceptions are when the expression is the operand of a unary & operator, when it's the operand of a unary sizeof operator, and when it's a string literal in an initializer used to initialize an array object. None of these exceptions applies here.

But there's an implicit assumption in that conversion: the pointer is to the first element of the array object.

Most array expressions -- almost all of them, in fact -- refer to some array object, such as a declared array variable, an element of a multidimensional array, and so forth. Functions can't return arrays, so you can't get a non-lvalue array expression that way.

But as you've seen, a function can return a struct that contains an array -- and there's no object associated with the array expression to_hex_string_(12345).a.

The new ISO C11 standard addresses this by adding new wording to the section describing storage durations. The N1570 draft, section 6.2.4p8, says:

A non-lvalue expression with structure or union type, where the structure or union contains a member with array type (including, recursively, members of all contained structures and unions) refers to an object with automatic storage duration and temporary lifetime. Its lifetime begins when the expression is evaluated and its initial value is the value of the expression. Its lifetime ends when the evaluation of the containing full expression or full declarator ends. Any attempt to modify an object with temporary lifetime results in undefined behavior.

In effect, this says that the returned value from your function (unlike most function results) is the value of a temporary object, allowing the decay of its array member to give you a (temporarily) valid pointer.

But until compilers fully support the new C standard (which won't be for some years), you'll just have to avoid referring to array members of returned structures.




回答3:


The problem you're facing is that : the variable result which is return is a local variable of the function _to_hex_string, that's means it is deleted at the end of the fonction call. so when you try to check it in the fonction test_hex it is no available any more.

To solve your problem you can deal with pointer.

here is your code modify

struct hex_string
{
    char a[9];
};

struct hex_string * to_hex_string_(unsigned x) // here you return a pointer
{
    static const char hex_digits[] = "0123456789ABCDEF";
    struct hex_string result;

    result = (struct hex_string *) malloc(sizeof(struct hex_string));
    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);  /* works */
}

Have I nice day



来源:https://stackoverflow.com/questions/7963813/printing-a-member-of-a-returned-struct

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!