5

In ISO C99, arrays that are not lvalues still decay to pointers, and may be subscripted, although they may not be modified or used after the next sequence point. (source)

I understand that this feature allows array indexing in cases where a function returning a structure containing an array, which is not allowed in C89 ( http://yarchive.net/comp/struct_return.html)

will you please help me understand why there is a restriction on using/modifying it after the next sequence point?

M.M
  • 138,810
  • 21
  • 208
  • 365
bare_metal
  • 1,134
  • 9
  • 20
  • 1
    Ok. I'm stymied. Where in the ISO C99 standard does it say that exact quote, as I can't find it anywhere . If you're going to cite the standards, please post the subsection, and if needed, paragraph mark, from whence you pulled the citation. – WhozCraig Sep 10 '14 at 07:30
  • @MattMcNabb Forward p7, I see your citation, not the OP's (and didn't expect to, as i'm intimately familiar with the frequency of "decay" in the standard). Thanks for the loc. (+1 on your answer). – WhozCraig Sep 10 '14 at 07:39
  • @WhozCraig updated my post w references – M.M Sep 10 '14 at 07:49

1 Answers1

7

Note, the text OP quoted is from GCC documentation. Relevant text from C99 to back up that quote is:

C99 6.5.2.2/5

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.

and also from the list of changes in the Foreword:

conversion of array to pointer not limited to lvalues

I don't have the C89 text to compare, but the C99 description of array-to-pointer conversion (6.3.2.1/3) does not mention any restriction on the array being an lvalue. Also, the C99 section on subscripting (6.5.2.1/2) talks about the expression being subscripted as postfix expression, it does not mention lvalues either.


Consider this code:

struct foo
{
     char buf[20];
};

struct foo foo(char const *p) { struct foo f; strcpy(f.buf, p); return f; }

int main()
{
     char *hello = foo("hello").buf;
     char *bye = foo("bye").buf;

     // other stuff...

     printf("%s\n", hello);
     printf("%s\n", bye);
}

Where do the pointers hello and bye point to? The purpose of this clause is to say that the compiler does not have to keep all of the returned objects hanging around in memory somewhere in order to make those pointers remain valid indefinitely.

Instead, the hello is only valid up until the next ; in this case (or next sequence point in general). This leaves the compiler free to implement returning structs by value as a hidden pointer parameter, as Chris Torek describes in his excellent post, which can be "freed" at the end of the current statement.

NB. The C99 situation isn't quite as simple as described in Chris's post, as the following has to work:

printf("%s %s\n", foo("hello").buf, foo("bye").buf);

My install of gcc 4.8 seems to get it right though - that works with -std=c99, and segfaults with -std=c89.

M.M
  • 138,810
  • 21
  • 208
  • 365