Struct assignment

G

Grey Alien

If I have the ff struct:

struct A
{
unsigned int i;
char s[LONG_ENOUGH];
} a, b;


And use them in code like this:

a.i = 42 ;
strcpy(a.s,"test");

b.i = 100 ;

b = a ;

at this point, a (bitwise?) copy of a is made to b. Question is:

1). is b.s now ptr to a.s ? (I think so)
If so, what happens if for instance variable 'a' goes out of scope (?)

2). Does the compiler generate an implicit "memcpy" or "memmove" behind
the scenes when it sees an assignment like this (to avoid dangling ptrs)?
 
M

Malcolm McLean

Grey Alien said:
If I have the ff struct:

struct A
{
unsigned int i;
char s[LONG_ENOUGH];
} a, b;


And use them in code like this:

a.i = 42 ;
strcpy(a.s,"test");

b.i = 100 ;

b = a ;

at this point, a (bitwise?) copy of a is made to b. Question is:

1). is b.s now ptr to a.s ? (I think so)
If so, what happens if for instance variable 'a' goes out of scope (?)

2). Does the compiler generate an implicit "memcpy" or "memmove" behind
the scenes when it sees an assignment like this (to avoid dangling ptrs)?
The answer is 2. A structure assignment will cause a call to memcpy to be
made, or equivalent code emitted if the structure is small enough to make
this wasteful and the compiler is clever.
However if structures contain pointers then the values of the pointers are
overwritten. So you have to be extremely careful not to orphan memory or
create peculiar bugs with aliases.
 
F

Flash Gordon

Grey Alien wrote, On 30/06/07 17:43:
If I have the ff struct:

struct A
{
unsigned int i;
char s[LONG_ENOUGH];
} a, b;


And use them in code like this:

a.i = 42 ;
strcpy(a.s,"test");

b.i = 100 ;

b = a ;

at this point, a (bitwise?) copy of a is made to b.

It is not a bitwise copy, it is a copy of all the elements in the struct.
> Question is:

1). is b.s now ptr to a.s ? (I think so)

Since b.s was not defined as a pointer, what makes you think an
assignment could magically transform it from being an array in to being
a pointer? You need to read section 6 of the comp.lang.c FAQ at
http://c-faq.com/ specifically the questions dealing with whether
pointers and arrays are the same thing.
If so, what happens if for instance variable 'a' goes out of scope (?)

2). Does the compiler generate an implicit "memcpy" or "memmove" behind
the scenes when it sees an assignment like this (to avoid dangling ptrs)?

It is very rare for C to do things behind your back. Had there been
pointers in your struct (which there were not) then after the assignment
they would point to the same place as they point in the original struct,
and when that place is no longer valid (an automatic that goes out of
scope, for example) the pointers are no longer valid.
 
T

Thomas Lumley

If I have the ff struct:

struct A
{
unsigned int i;
char s[LONG_ENOUGH];

} a, b;

And use them in code like this:

a.i = 42 ;
strcpy(a.s,"test");

b.i = 100 ;

b = a ;

at this point, a (bitwise?) copy of a is made to b.
Question is:

1). is b.s now ptr to a.s ? (I think so)

I think you are confusing arrays and pointers. Since a.s is an array,
a.s[0] to a.s[LONG_ENOUGH-1] are actually stored in the structure and
are copied by the assignment.

If a.s were just a pointer to memory allocated elsewhere the
assignment would just copy the pointer.
2). Does the compiler generate an implicit "memcpy"
or "memmove" behind the scenes when it sees an
assignment like this (to avoid dangling ptrs)?

There is an explicit copy since a.s is an array. If a.s
were a pointer there would not be an implicit copy, and
Bad Things such as dangling pointers could result.

-thomas
 
S

Serve Lau

Flash Gordon said:
Grey Alien wrote, On 30/06/07 17:43:
If I have the ff struct:

struct A
{
unsigned int i;
char s[LONG_ENOUGH];
} a, b;


And use them in code like this:

a.i = 42 ;
strcpy(a.s,"test");

b.i = 100 ;

b = a ;

at this point, a (bitwise?) copy of a is made to b.

It is not a bitwise copy, it is a copy of all the elements in the struct.
Question is:

1). is b.s now ptr to a.s ? (I think so)

Since b.s was not defined as a pointer, what makes you think an assignment
could magically transform it from being an array in to being a pointer?
You need to read section 6 of the comp.lang.c FAQ at http://c-faq.com/
specifically the questions dealing with whether pointers and arrays are
the same thing.

Its easy to see where the confusion comes from. There are situations where
pointers degenerate into pointers , the OP probably had that in mind
 
F

Flash Gordon

Serve Lau wrote, On 30/06/07 19:53:
Its easy to see where the confusion comes from. There are situations where
pointers degenerate into pointers , the OP probably had that in mind

In my opinion it is only easy to confuse arrays and pointers if it is
badly taught. If arrays and pointers are taught as fundamentally
different concepts and *then* the way array names degenerate to pointers
to the first element is explained there will not be anything like the
problems. In one-to-one sessions I've been able to explain the basics of
arrays pointers to non-computer people in minutes (I needed to so I
could explain approximately what was the cause of a problem), although I
did not go on to how things are done in C.
 
R

Richard Heathfield

Serve Lau said:

Its easy to see where the confusion comes from. There are situations
where pointers degenerate into pointers ,

Pointers always degenerate into pointers.
 
K

Keith Thompson

Flash Gordon said:
Grey Alien wrote, On 30/06/07 17:43:
If I have the ff struct:
struct A
{
unsigned int i;
char s[LONG_ENOUGH];
} a, b;
And use them in code like this:
a.i = 42 ;
strcpy(a.s,"test");
b.i = 100 ;
b = a ;
at this point, a (bitwise?) copy of a is made to b.

It is not a bitwise copy, it is a copy of all the elements in the struct.

Yes -- and that can be, and commonly is, implemented as a bitwise copy
of the struct.

Suppose there's a gap between the members "i" and "s". After the
assignment "b = a;", the gaps in "a" and "b" may or may not have the
same contents. The assignment can be done either as a bitwise copy or
by copying the members one-by-one, leaving any gaps alone.

99% of the type, this doesn't matter because you're never going to
look at what's in the gaps anyway.
 
F

Flash Gordon

Richard Heathfield wrote, On 30/06/07 20:56:
Serve Lau said:



Pointers always degenerate into pointers.

No they don't, they stay as pointers ;-)

Knowing what Serve Lau must have intended I read it as "where arrays
degenerate...".
 
F

Flash Gordon

Keith Thompson wrote, On 30/06/07 21:30:
Flash Gordon said:
Grey Alien wrote, On 30/06/07 17:43:
If I have the ff struct:
struct A
{
unsigned int i;
char s[LONG_ENOUGH];
} a, b;
And use them in code like this:
a.i = 42 ;
strcpy(a.s,"test");
b.i = 100 ;
b = a ;
at this point, a (bitwise?) copy of a is made to b.
It is not a bitwise copy, it is a copy of all the elements in the struct.

Yes -- and that can be, and commonly is, implemented as a bitwise copy
of the struct.

Suppose there's a gap between the members "i" and "s". After the
assignment "b = a;", the gaps in "a" and "b" may or may not have the
same contents. The assignment can be done either as a bitwise copy or
by copying the members one-by-one, leaving any gaps alone.

99% of the type, this doesn't matter because you're never going to
look at what's in the gaps anyway.

Where there are multiple representations for the same value the
representation could change. It is important for the OP to know this
IMHO so that s/he does not assume that memcmp can be used safely.
 
R

Richard Heathfield

Flash Gordon said:
Richard Heathfield wrote, On 30/06/07 20:56:

No they don't, they stay as pointers ;-)

Knowing what Serve Lau must have intended I read it as "where arrays
degenerate...".

I know. Actually, arrays never actually do that. We often say they do,
but we're just being lazy. What we really mean is that the name of an
array, when used in an expression, is often (indeed, *usually*) treated
as if it were a pointer to the array's first element. The array itself
never "degenerates" (or "decays", as it is usually put) at all.
 
A

Army1987

Grey Alien said:
If I have the ff struct:

struct A
{
unsigned int i;
char s[LONG_ENOUGH];
} a, b;


And use them in code like this:

a.i = 42 ;
strcpy(a.s,"test");

b.i = 100 ;

b = a ;

at this point, a (bitwise?) copy of a is made to b. Question is:

1). is b.s now ptr to a.s ? (I think so)
No, since it is an array, not a pointer.
If so, what happens if for instance variable 'a' goes out of scope (?)

2). Does the compiler generate an implicit "memcpy" or "memmove" behind the scenes when it sees an assignment like this?
It could, but it needn't. For example, padding bits needn't be
copied.
 
E

Eric Sosman

Malcolm McLean wrote On 06/30/07 13:05,:
If I have the ff struct:

struct A
{
unsigned int i;
char s[LONG_ENOUGH];
} a, b;


And use them in code like this:

a.i = 42 ;
strcpy(a.s,"test");

b.i = 100 ;

b = a ;

at this point, a (bitwise?) copy of a is made to b. Question is:

1). is b.s now ptr to a.s ? (I think so)
If so, what happens if for instance variable 'a' goes out of scope (?)

2). Does the compiler generate an implicit "memcpy" or "memmove" behind
the scenes when it sees an assignment like this (to avoid dangling ptrs)?

The answer is 2. A structure assignment will cause a call to memcpy to be
made, or equivalent code emitted if the structure is small enough to make
this wasteful and the compiler is clever. [...]

The compiler *may* do this, but it is not required
to copy padding bytes and padding bits. Assignment only
copies the value; padding bytes and bits are not part of
the value of a struct, and might not be copied -- as they
would be if memcpy() or an equivalent were used.
 
O

Old Wolf

The compiler *may* do this, but it is not required
to copy padding bytes and padding bits. Assignment only
copies the value; padding bytes and bits are not part of
the value of a struct, and might not be copied -- as they
would be if memcpy() or an equivalent were used.

Something that just occurred to me. Say we
have:
struct S
{
char s[10];
};

struct S s = { "hello" };
struct S t;
t = s;

Initializing an automatic array from a string
literal is only guaranteed to initialize the
characters of the string and the null terminator
- it could leave subsequent array entries (in
this case, indices 6 through 9) uninitialized.

So does the assignment 't = s' cause undefined
behaviour by copying the values of uninitialized
array members?
 
R

Robert Gamble

The compiler *may* do this, but it is not required
to copy padding bytes and padding bits. Assignment only
copies the value; padding bytes and bits are not part of
the value of a struct, and might not be copied -- as they
would be if memcpy() or an equivalent were used.

Something that just occurred to me. Say we
have:
struct S
{
char s[10];
};

struct S s = { "hello" };
struct S t;
t = s;

Initializing an automatic array from a string
literal is only guaranteed to initialize the
characters of the string and the null terminator
- it could leave subsequent array entries (in
this case, indices 6 through 9) uninitialized.

Actually you are wrong about that, 9899:1999 §6.7.8p21:

"If there are fewer initializers in a brace-enclosed list than there
are elements or members
of an aggregate, or fewer characters in a string literal used to
initialize an array of known
size than there are elements in the array, the remainder of the
aggregate shall be
initialized implicitly the same as objects that have static storage
duration."

Robert Gamble
 
K

Keith Thompson

Old Wolf said:
The compiler *may* do this, but it is not required
to copy padding bytes and padding bits. Assignment only
copies the value; padding bytes and bits are not part of
the value of a struct, and might not be copied -- as they
would be if memcpy() or an equivalent were used.

Something that just occurred to me. Say we
have:
struct S
{
char s[10];
};

struct S s = { "hello" };
struct S t;
t = s;

Initializing an automatic array from a string
literal is only guaranteed to initialize the
characters of the string and the null terminator
- it could leave subsequent array entries (in
this case, indices 6 through 9) uninitialized.

So does the assignment 't = s' cause undefined
behaviour by copying the values of uninitialized
array members?

Not in n1124. n1124 6.2.6.1p6 says:

The value of a structure or union object is never a trap
representation, even though the value of a member of the structure
or union object may be a trap representation.

but that wording is not in the original C99 standard, or in C90; C99
instead says:

The values of padding bytes shall not affect whether the value of
such an object is a trap representation. Those bits of a structure
or union object that are in the same byte as a bit-field member,
but are not part of that member, shall similarly not affect
whether the value of such an object is a trap representation.

I suspect that the intent all along was that your example would not
invoke undefined behavior, but it had never been stated properly,
which is why it needed to be corrected in n1124.

By a strict reading of the original C99 or C90 standard, I think it
could be argued that your example does invoke undefined behavior. I'd
be interested in seeing an argument that it doesn't.
 
K

Keith Thompson

Robert Gamble said:
Something that just occurred to me. Say we
have:
struct S
{
char s[10];
};

struct S s = { "hello" };
struct S t;
t = s;

Initializing an automatic array from a string
literal is only guaranteed to initialize the
characters of the string and the null terminator
- it could leave subsequent array entries (in
this case, indices 6 through 9) uninitialized.

Actually you are wrong about that, 9899:1999 §6.7.8p21:

"If there are fewer initializers in a brace-enclosed list than there
are elements or members of an aggregate, or fewer characters in a
string literal used to initialize an array of known size than there
are elements in the array, the remainder of the aggregate shall be
initialized implicitly the same as objects that have static storage
duration."

Argh, you're right. My comment about n1124 6.2.6.1p6 do not apply to
the above example.

They do, however, apply to the following:

struct S
{
char s[10];
};

struct S s;
struct S t;
strcpy(s.s, "hello");
t = s;

(Assume that this appears inside a function definition, and that a
"#include <string.h>" is visible.)
 
P

Peter Nilsson

Richard Heathfield said:
Flash Gordon said:

I know. Actually, arrays never actually do that. We often
say they do, but we're just being lazy. What we really
mean is that the name of an array, when used in an
expression, is often (indeed, *usually*) treated as if it
were a pointer to the array's first element.

The effect is not limited to named arrays...

int (*ap)[20] = malloc(sizeof *ap);
int *ip = *ap;
The array itself never "degenerates" (or "decays", as it
is usually put) at all.

There is change from an aggregate type to a non-aggregate type.
We could say 'converted' as the standard does, but decay is
more descriptive and notwithstanding. I don't see that as being
'lazy'.
 
R

Richard Heathfield

Old Wolf said:

Something that just occurred to me. Say we
have:
struct S
{
char s[10];
};

struct S s = { "hello" };
struct S t;
t = s;

Initializing an automatic array from a string
literal is only guaranteed to initialize the
characters of the string and the null terminator
- it could leave subsequent array entries (in
this case, indices 6 through 9) uninitialized.

Not so. A part-initialisation is sufficient to invoke the static default
initialiser rule.
So does the assignment 't = s' cause undefined
behaviour by copying the values of uninitialized
array members?

No, because there aren't any.
 
B

Barry Schwarz

Richard Heathfield said:
Flash Gordon said:

I know. Actually, arrays never actually do that. We often
say they do, but we're just being lazy. What we really
mean is that the name of an array, when used in an
expression, is often (indeed, *usually*) treated as if it
were a pointer to the array's first element.

The effect is not limited to named arrays...

int (*ap)[20] = malloc(sizeof *ap);
int *ip = *ap;
The array itself never "degenerates" (or "decays", as it
is usually put) at all.

There is change from an aggregate type to a non-aggregate type.
We could say 'converted' as the standard does, but decay is
more descriptive and notwithstanding. I don't see that as being
'lazy'.

Why generate new words to describe what the standard explains very
clearly. With three exception, an expression of array type
**evaluates** to the address of the first element with type pointer to
element type. No decay, no degeneration, no change from aggregate to
non-aggregate, no conversion. Just an evaluation.


Remove del for email
 

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,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top