Array assignment via cast

J

James Mcguire

Hi,

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};

is this possible with an array?
eg char test[10];

.... is it possible to assign to test via a cast? is it legal?

Thanks
 
R

Richard Bos

James Mcguire said:
I frequently do non-initialisation type structure assignment via casting:
mys=(struct s){3,4,5};

is this possible with an array?

No. An array is not a modifiable lvalue, and therefore cannot be
assigned to. It _can_ be initialised, but that's another part of the
syntax (using identically-spelled tokens, but that makes no difference).

Richard
 
L

Lawrence Kirby

Hi,

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 a cast, it is called a compound literal and is a "new" feature
introduced in C99. If you aren't targetting C99 compilers specifically you
probably shouldn't use it.
is this possible with an array?
eg char test[10];

Arrays are not modifiable lvalues and cannot be assigned to. Probably the
nearest you can get is something like

static const char initdata[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
memcpy(test, initdata, sizeof test);

Lawrence
 
C

Chris Torek

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.)
 
K

Keith Thompson

Chris Torek said:
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.)
[...]

Another good reason not to call it a cast is that it isn't one.

A cast-expression looks like:

( type-name ) expression

(that's a bit of an over-simplification for reasons that aren't
relevant to this discussion). The operand has to be an expression,
which is converted to the named type.

In a compound literal, the

{ list-of-values }

is not an expression, and no conversion takes place; instead, the
type-name tells the compiler what the type of the expression is. The
only thing it has in common with a cast is that it includes a type
name in parentheses.
 
J

Jonathan Burd

rss said:
Thank you for your incredibly detailed and concise answer.

I have a off-topic question; it's becoming apparent that in order to become
a more effective C programmer I need to learn more about the standard.
What is the best way of perusing this? I took a look at the FAQ and have
access to a copy of the C99 standard, but it seems incredibly dense reading
that doesn't seem to make much sense to a person mof my experience. Are
there any alternative sources of information that would help?

Thanks

This place itself is a definitive resource. Keep reading. ;)

Regards,
Jonathan.

--
C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
C Library: http://www.dinkumware.com/refxc.html
C99 Standard Draft: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n869/

"I'm learning to program because then I can write
programs to do my homework faster." - Andy Anfilofieff
 
F

Flash Gordon

rss said:
Thank you for your incredibly detailed and concise answer.

I have a off-topic question; it's becoming apparent that in order to become
a more effective C programmer I need to learn more about the standard.
What is the best way of perusing this? I took a look at the FAQ and have
access to a copy of the C99 standard, but it seems incredibly dense reading
that doesn't seem to make much sense to a person mof my experience. Are
there any alternative sources of information that would help?

I would suggest getting a copy of The C Programming Language, Second
Edition, by Kernighan & Ritchie. It is the main reference that I use.
The only system specific stuff is one chapter called The UNIX System
Interface which is fairly obvious, the rest is all portable.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top