Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

arrays that are not lvalues and sequence point restriction

Tags:

c

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?

like image 642
bare_metal Avatar asked Sep 10 '14 07:09

bare_metal


1 Answers

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.

like image 53
M.M Avatar answered Sep 23 '22 09:09

M.M