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