I frequently do non-initialisation type structure assignment via casting:
e.g.
struct s{int i,j,k;} mys;
...
mys=(struct s){3,4,5};
This is not actually a cast. It is instead a C99-standard form
called a "compound literal". The syntax for a compound literal
is:
( type-name ) { list-of-values }
and of course the (, type-name, ) sequence looks exactly like a
cast. (So why not call it one? Well, because the C99 standard
calls it something else -- so if you want to communicate with
C programmers who have read the C99 standard, or a good book
about C99, presumably you would want to use the same words. Also,
because you can include the "const" qualifier to good effect.)
is this possible with an array?
eg char test[10];
No. You can construct a compound-literal with array type:
(const char [10]){'a', 'b', 'c'}
has a pretty similar meaning to:
"abc\000\000\000\000\000\000"
Both of these produce an anonymous array object containing 10
"char"s (note that the string literal has 9 characters in it, a +
b + c + six copies of \000 + the terminating '\0' that is always
included for string literals = 10 chars). Both are allowed to
place the array in read-only storage. The biggest difference
between the two is that, in a quirk having to do with history, the
string literal produces the type "array 10 of char" while the
compound literal has type "array 10 of const char".
(String-literal-produced arrays really should have "const char",
but ancient C had no "const" type, and this would have invalidated
huge quantities of existing code, had the 1989 C standard made
them "const".)
The problem is, even having produced an array object, you cannot
assign it to another array:
struct s s1, s2;
...
s1 = s2; /* is OK */
but:
char a1[10], a2[20];
...
a1 = a2; /* not OK, requires a diagnostic */
... is it possible to assign to test via a cast? is it legal?
Again, it is not a cast, it is a "compound literal"; and no, ordinary
assignment will not work, just as it does not work with actual
array objects: the left hand side, a1 in the example above, is not
a "modifiable lvalue", and the right hand side expression undergoes
the transform prescribed by The Rule, becoming a pointer value.
Hence, just as you must memcpy() or strcpy() arrays or strings
into their target buffers, you must also memcpy() the compound
literal:
assert(sizeof a1 <= sizeof a2); /* assumed in memcpy call */
memcpy(a1, a2, sizeof a1); /* copy the parts of a2 that fit */
...
memcpy(a1, (const char [sizeof a1]){'a', 'b', 'c'}, sizeof a1);
Note that if you leave out the "const" in a compound literal, the
compiler is obligated to create a fresh copy whenever the enclosing
block is entered, in case you take a pointer to the literal and
then modify it:
% cat t.c
#include <stdio.h>
int main(void) {
for (int i = 0; i < 3; i++) {
char *p = (char []) { 'h', 'e', 'l', 'l', 'o', '\0' };
if (i == 1)
p[0] = 'j';
puts(p);
}
return 0;
}
% cc -std=c99 -O -o t t.c -W -Wall
% ./t
hello
jello
hello
%
This means that the non-"const" version generally invokes an internal
memcpy() from a "clean" copy each time the block is entered. Using
the "const" can avoid paying for these copies. (A smart compiler
will attempt to figure out whether the copy is required, but using
"const" can save programmer effort too, as the programmer no longer
has to wonder whether the compound literal ever gets modified.)
(GCC seems to make a copy every time, even when the compound literal
uses "const". This probably has to do with "gcc -std=c99" not
actually implementing C99, but rather something somewhere between
GNUC and C99. I suspect the GNUC language did not have this special
"one static copy is OK" property for const-qualified compound
literals.)