6

I have a function returning a union type. Is it allowed by the standard (C99) to access a field of a returned value directly from the call without copying the value to a variable. Here an example to illustrate what I mean:

union thinga { int integ; char arr[4]; };

union thinga f(void)
{
  union thinga t = {.integ = 1};
  return t;
}
int main(void)
{
   printf("thinga is %d\n", f().integ);
}

Is the call with field f().integ allowed? In my example it's a union but the issue is the same for struct. I ask the question, because I remember vividly that gcc 3.3 on Solaris didn't like this construct and would warn like hell. Its problem was that it had to generate internally an invisible variable to be able to access the field of the struct or the union. Newer compilers seem not to mind the construct but I would like to know if there is a hidden catch (i.e. undefined bevaviour that I didn't think of.

EDIT: Ok it looks like my contrived example is a bit too simple and as commenter 2501 noticed by giving links to array decaying to pointer on out of scope objects, let's see if we are in the same situation if I change a bit my code.

 union thinga f(const char *val)
 {
   union thinga t = {.integ = 0};
   t.arr[0] = val[0];
   return t;
 }

 int main(void)
 {
     printf(" thinga.integ=%d .arr=%s\n", f("1").integ, f("1").arr);
 }

is this case the same as given in arrays that are not lvalues and sequence point restriction and Undefined behavior: when attempting to access the result of function call ? (the value returned are obviously impementation dependend (endiannes) but that is not the issue here).

Nonemoticoner
  • 650
  • 5
  • 14
Patrick Schlüter
  • 11,394
  • 1
  • 43
  • 48
  • Apparently the function always returns an `int`. So why using a `union`? – too honest for this site Mar 16 '16 at 15:45
  • 2
    You might be surprised if you use `arr` member: https://stackoverflow.com/questions/25759295/arrays-that-are-not-lvalues-and-sequence-point-restriction/25759612#25759612 It seems ub in C99: https://stackoverflow.com/questions/13755628/undefined-behavior-when-attempting-to-access-the-result-of-function-call/13755846#13755846 – 2501 Mar 16 '16 at 15:51
  • Just a contrived example for the question. In my real project the union has 3 different fields that are accessed differently in different modules. There would be no point in over complexifying the example. – Patrick Schlüter Mar 16 '16 at 15:54
  • 1
    @2501: C standard is C11, not C99. Do you have any idea how that is with C11? How do you mean that anyway? The function returns a `union`. The member-operator `.` then is applied like to a named union variable. – too honest for this site Mar 16 '16 at 16:07
  • @Olaf OP is asking about C99. For C11, see temporary lifetime in the second link. – 2501 Mar 16 '16 at 16:09
  • @2501: OP asks how this is in the standard, which would be C11, not C99. Maybe he has the wrong assumption C99 still is the standard. The C tag also is clearly referencing the C standard, not some older version. That's what the c99, etc. tags are for. He should clarify. – too honest for this site Mar 16 '16 at 16:10
  • @PatrickSchlüter The second link explains this for both C99 and C11. IMO this is a duplicate of that question. – 2501 Mar 16 '16 at 16:12
  • "Is it allowed by **the** standard (C99)" - C standard is currently C11, not C99. Do you ask about the **previous** standard (which is C99) or do you mean the C standard (aka C11)? – too honest for this site Mar 16 '16 at 16:12
  • 1
    @2501, yes, I should have read the link till the end before editing my question :-) It gives exactly the answer I needed. Could you make your comment as an answer so that I can give you the "right answer" points? – Patrick Schlüter Mar 16 '16 at 16:15
  • @Olaf I asked for C99, because that is officially what our project is supposed to be conformant with, but you're right that current standard is C11. – Patrick Schlüter Mar 16 '16 at 16:17
  • 1
    So just a small recommendation: Please don't use the term "the standard" when not asking about **the** standard like canceled versions. – too honest for this site Mar 16 '16 at 16:26
  • @PatrickSchlüter Please vote to close as a duplicate. – 2501 Mar 16 '16 at 16:28

2 Answers2

3

This is valid and allowed by c standard and there is no undefined behavior in this code.

EDIT: For the snippet

 int main(void)
 {
     printf(" thinga.integ=%d .arr=%s\n", f("1").integ, f("1").arr);
 }  

f("1").arr is referencing arr element of the union. Since arr is an array and as per C rule, in this context array will decay to pointer to its first element. Since t is local to the function (an automatic local variable and will no longer be exist once function return), accessing arr elements will invoke undefined behavior.

haccks
  • 104,019
  • 25
  • 176
  • 264
0

This is just identical to

printf("thinga is %d\n", (union thinga) {.integ = 1}.integ);

, which is obviously well-defined.

nalzok
  • 14,965
  • 21
  • 72
  • 139