struct assignment and indeterminate values

S

Seebs

While reading up on some of the stuff in C:TCR, I've found something which
looks as though it used to be an error but possibly isn't.

Consider:
int main(void) {
struct { int a, b; } x, y;
x.a = 10;
y = x;
return 0;
}

Is the behavior of this program well-defined? My assumption would have been
that it was not, because x.b was indeterminate and accessed through an lvalue
of non-character type. However, C99 TC3 says (6.2.6.1, paragraph 3):
"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 may be a trap representation".

That looks as though, after the assignment, no undefined behavior has occurred,
but it is possible that y.b is a trap representation. Interestingly, it looks
as though this might be true even if y had been fully initialized before the
assignment from x.

Thoughts?

-s
 
E

Ersek, Laszlo

While reading up on some of the stuff in C:TCR, I've found something which
looks as though it used to be an error but possibly isn't.

Consider:
int main(void) {
struct { int a, b; } x, y;
x.a = 10;
y = x;
return 0;
}

Is the behavior of this program well-defined? My assumption would have been
that it was not, because x.b was indeterminate and accessed through an lvalue
of non-character type. However, C99 TC3 says (6.2.6.1, paragraph 3):
"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 may be a trap representation".

That looks as though, after the assignment, no undefined behavior has occurred,
but it is possible that y.b is a trap representation. Interestingly, it looks
as though this might be true even if y had been fully initialized before the
assignment from x.

Thoughts?

Is there any rationale for the quoted passage of TC3? What you wrote made
me remember C99 6.2.6.1p6, footnote 42: "Thus, for example, structure
assignment may be implemented element-at-a-time or via memcpy." (I seem to
remember somebody mention that footnotes are not normative.)

I also remember a warning issued by gcc for a similar case.

http://lists.debian.org/debian-mentors/2009/10/msg00474.html

I could not reproduce that warning now with your code, though.

Cheers,
lacos
 
S

Seebs

Is there any rationale for the quoted passage of TC3?

I don't know. It's a change from TC1.

TC1:

When a value is stored in an object of structure or union type,
including in a member object, the bytes of the object representation
that correspond to any padding bytes take unspecified values.(42)
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.

TC2:

When a value is stored in an object of structure or union
type, including in a member object, the bytes of the object
representation that correspond to any padding bytes take
unspecified values.(42) 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.

So there is a change there as of TC2, but I don't know the history.

I think it is probably intended specifically to address the case of
structure assignment, although it seems like that may be contradicted
by footnote 42. (And yes, footnotes are non-normative.)
I could not reproduce that warning now with your code, though.

It could be that gcc has changed the handling of that case on the grounds
that the standard has clarified its intent. I'm not sure.

-s
 
P

Peter Nilsson

Seebs said:
...C99 TC3 says (6.2.6.1, paragraph 3):
 "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 may be a trap representation".
Thoughts?

Consider a struct record where not every field requires
a value in certain contexts. For example, consider a
simple token record...

struct token
{
int kind;
union {
maxint_t u;
long double d;
int keyword;
...
} detail;
};

If one of the 'kind's does not require a detail (e.g.
whitespace,) should the language still insist that one
of the union members be filled in when such a token is
assigned to another token object?

The TC just legalised a construct that has long been
taken for granted.
 
S

Seebs

If one of the 'kind's does not require a detail (e.g.
whitespace,) should the language still insist that one
of the union members be filled in when such a token is
assigned to another token object?

I would have thought it did!
The TC just legalised a construct that has long been
taken for granted.

As someone who never took it for granted, I am not totally sold on
this; I have been carefully initializing the whole structure all along.

However, I certainly grant that no great injury is done to the language
by permitting this.

Thanks for pointing out this case, where the nature of the structure's
usage suggests strongly that it's undesireable to be forced to initialize
a field with no meaningful values.

-s
 
K

Keith Thompson

Peter Nilsson said:
Consider a struct record where not every field requires
a value in certain contexts. For example, consider a
simple token record...

struct token
{
int kind;
union {
maxint_t u;
long double d;
int keyword;
...
} detail;
};

If one of the 'kind's does not require a detail (e.g.
whitespace,) should the language still insist that one
of the union members be filled in when such a token is
assigned to another token object?

The TC just legalised a construct that has long been
taken for granted.

Here's an example that I find clearer:

struct string {
size_t len;
char str[MAX_LEN];
};

struct string hello;
hello.len = 5;
strcpy(hello.str, "hello");

There's no need to initialize elements of hello.str past the ones that
are actually in use.

(Yeah, char doesn't have trap representations; consider a similar
example with an array of double.)
 
T

Tim Rentsch

Seebs said:
While reading up on some of the stuff in C:TCR, I've found something which
looks as though it used to be an error but possibly isn't.

Consider:
int main(void) {
struct { int a, b; } x, y;
x.a = 10;
y = x;
return 0;
}

Is the behavior of this program well-defined? My assumption would have been
that it was not, because x.b was indeterminate and accessed through an lvalue
of non-character type. However, C99 TC3 says (6.2.6.1, paragraph 3):
"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 may be a trap representation".

That looks as though, after the assignment, no undefined behavior has occurred,
but it is possible that y.b is a trap representation. Interestingly, it looks
as though this might be true even if y had been fully initialized before the
assignment from x.

Thoughts?

The value of a structure is NEVER [my emphasis] a trap representation.

Hence, the assignment 'y = x;' is always defined, even if
any _or all_ of the members of 'x' hold trap representations.

(There is a change in C1X that would let 'y = x;' be undefined
behavior (I think) if no assignment has been done to a member
of 'x'. However, this code

struct { int a, b; } x[1], y[1];
y[0] = x[0];

is always defined behavior, even with no member assignments
to 'x[0]', even under the new C1X rules.)
 

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

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top