C
CBFalconer
Jack said:.... snip ...
Correct conclusion, oversimplified and incorrect explanation, Chuck.
True. However my statement is the limitation I impose on myself.
Jack said:.... snip ...
Correct conclusion, oversimplified and incorrect explanation, Chuck.
CBFalconer said:True. However my statement is the limitation I impose on myself.
No problem, except that you are using a name not available to you.
Names with a leading '_' char are reserved for the implementation.
The thing you CAN'T do is compare structs for equality. i.e.:
if (foo == bar) ...
is illegal. The == operator doesn't know where there may be
padding.
Unlikely, because structs aren't pointers! There's no intrinsic
reason why == couldn't be made to work for structs, deep comparison
and all.
It's possible, however, that I've misunderstood your point, and that
there is a similarity between structure comparison and pointer
comparison that I've overlooked. If so, care to explain?
qarnos said:Actually, I was thinking more of structs containing pointers. For
example, a struct containing a pointer to a char string. Should the
structs compare equal if the strings contain the same symbols, but
with different storage address'?
Another issue with automagic deep-comparison would be structs which
contain pointers to themselves. Talk about a can of worms!
Richard said:qarnos said:
Unlikely, because structs aren't pointers! There's no
intrinsic reason why == couldn't be made to work for structs,
deep comparison and all.
Golden said:Need not be a violation, but the compiler would have to zero the bits of the
union not being used for the type stored into it. As this would be a
performance hit, a compile time switch could be set.
Yes. What should == mean in the case of pointers inside a structure?
int *a;
int *b;
if (a == b)
if (*a == *b)
Golden California Girls said:Need not be a violation, but the compiler would have to zero the bits of the
union not being used for the type stored into it. As this would be a
performance hit, a compile time switch could be set.
Yes. What should == mean in the case of pointers inside a structure?
int *a;
int *b;
if (a == b)
if (*a == *b)
Golden California Girls said:Need not be a violation, but the compiler would have to zero the bits of the
union not being used for the type stored into it. As this would be a
performance hit, a compile time switch could be set.
Yes. What should == mean in the case of pointers inside a structure?
int *a;
int *b;
if (a == b)
if (*a == *b)
It wouldn't just be a performance hit, it would be nearly impossible
to implement. Consider:union u {
char c;
int i;
};void set_char(char *ptr, char value)
{
*ptr = value;
}int main(void)
{
union u x;
union u y;x.i = 12345;
y.i = 54321;
x.c = '*';
set_char(&y.c, '*');if (x == y) {
/* ? */
}
return 0;
}The compiler might zero the excess bytes of x when assigning '*' to
x.c, but when it sees ``*ptr = value;'', it has no way of knowing that
it's assigning a value to a union member. The compiler would not only
have to keep track of which member of a union is current, it would
have to propagate this information to code that doesn't refer to any
unions.
When it does ``*ptr = value;'' in a separate translation unit [going farther
than your example] it sure doesn't. When it sees ``set_char(&y.c, '*');'' it
does know and should assume that the called function knows nothing and zero the
excess bytes of the pointers object.
I'm not saying this would be easy or even desirable. There may be some
construction that does make it impossible, right now I can't think of one..
If struct comparison were allowed, I think shallow comparison would be
the only way to go. But since logical equality very often either is
meaningless or corresponds to something other than shallow
member-by-member equality, it can be argued that it's not worth adding
to the language; if you want to compare structs, you can write the
code yourself.
One of those camel nose in the tent things about allowing structure assignment ...
I think we are actually exploring the weakness of the union in C. I believe it
was a necessary evil to break the strict type checking
Golden California Girls said:Keith said:It wouldn't just be a performance hit, it would be nearly impossible
to implement. Consider:
union u {
char c;
int i;
};
void set_char(char *ptr, char value)
{
*ptr = value;
}
int main(void)
{
union u x;
union u y;
x.i = 12345;
y.i = 54321;
x.c = '*';
set_char(&y.c, '*');
if (x == y) {
/* ? */
}
return 0;
}
The compiler might zero the excess bytes of x when assigning '*' to
x.c, but when it sees ``*ptr = value;'', it has no way of knowing that
it's assigning a value to a union member. The compiler would not only
have to keep track of which member of a union is current, it would
have to propagate this information to code that doesn't refer to any
unions.
When it does ``*ptr = value;'' in a separate translation unit [going
farther than your example] it sure doesn't. When it sees
``set_char(&y.c, '*');'' it does know and should assume that the
called function knows nothing and zero the excess bytes of the
pointers object.
I'm not saying this would be easy or even desirable. There may be some
construction that does make it impossible, right now I can't think
of one.
On 11 Mar, 02:26, Golden California Girls <[email protected]>
wrote: [...]I think we are actually exploring the weakness of the union in
C. I believe it was a necessary evil to break the strict type
checking
I'm not convinced union *was* necessary. I never use it. If I want to
subvert the type system I find other ways. union does get used as a
hack to find the alignment needed by malloc and friends (a union
of all types will be correctly aligned for, er, all types)
Keith Thompson said:You can do the same thing with a struct rather than a union, but using
a union saves space and can be used to match an externally imposed
layout.
Golden California Girls said:Ben said:Golden California Girls said:Keith Thompson wrote:union u {
char c;
int i;
};
void set_char(char *ptr, char value)
{
*ptr = value;
}
int main(void)
{
union u x;
union u y;
x.i = 12345;
y.i = 54321;
x.c = '*';
set_char(&y.c, '*');
if (x == y) {
/* ? */
}
return 0;
}
The compiler might zero the excess bytes of x when assigning '*' to
x.c, but when it sees ``*ptr = value;'', it has no way of knowing that
it's assigning a value to a union member. The compiler would not only
have to keep track of which member of a union is current, it would
have to propagate this information to code that doesn't refer to any
unions.
When it does ``*ptr = value;'' in a separate translation unit [going
farther than your example] it sure doesn't. When it sees
``set_char(&y.c, '*');'' it does know and should assume that the
called function knows nothing and zero the excess bytes of the
pointers object.
You have a typo so am guessing a bit. Do you mean that the compiler
zeros the other bytes in the union at the point it generates
the set_char call? If so, that would be wrong since it does not know
that set_char will set the char (despite the name).
Yes. It doesn't know and except in the case of breaking UB it
doesn't matter either.
Is there a sequence point in there or is the function call itself
UB?
Yes I know what you intend, but without seeing the internals of
some_function and absent a const it could store values in both y.i
and y.c for return. That of course is UB as things stand now.
Golden California Girls said:Ben said:Golden California Girls said:Ben Bacarisse wrote:
Keith Thompson wrote:union u {
char c;
int i;
};
void set_char(char *ptr, char value)
{
*ptr = value;
}
int main(void)
{
union u x;
union u y;
x.i = 12345;
y.i = 54321;
x.c = '*';
set_char(&y.c, '*');
if (x == y) {
/* ? */
}
return 0;
}
The compiler might zero the excess bytes of x when assigning '*' to
x.c, but when it sees ``*ptr = value;'', it has no way of knowing that
it's assigning a value to a union member. The compiler would not only
have to keep track of which member of a union is current, it would
have to propagate this information to code that doesn't refer to any
unions.
When it does ``*ptr = value;'' in a separate translation unit [going
farther than your example] it sure doesn't. When it sees
``set_char(&y.c, '*');'' it does know and should assume that the
called function knows nothing and zero the excess bytes of the
pointers object.
You have a typo so am guessing a bit. Do you mean that the compiler
zeros the other bytes in the union at the point it generates
the set_char call? If so, that would be wrong since it does not know
that set_char will set the char (despite the name).
Yes. It doesn't know and except in the case of breaking UB it
doesn't matter either.
I'm sorry, I can't see why it does not matter. If set_char is badly
named because its purpose is to print the representation of the union
(and a char pointer to any member will do as the pointer to use for
that) then the compiler can't zero anything. If it sets that char
member, then zeroing the other bytes is fine, but how can the compiler
tell?
It can tell because you told it via the .something. Until you did
that the compiler knew the size of the object was the size of the
entire union. Once you change to .something the compiler knows the
size of .something and is free to to anything at all with the rest
of the union.
You can take the address of both. The UB is more basic than that.
For a second drop the union idea and simply pass the address of the
same int to this black box function.
void blackbox(int *i, int *j);
.
int k;
blakcbox(&k, &k);
If blackbox only reads i and j there is no UB. In any other case
there is the possibility of UB. Blackbox might save a value to i
and then read j. It might save to both but which order?
The compiler is free to assume the worst case as I believe the
standard does too and issue a diagnostic.
.... snip ...
I'm not convinced union *was* necessary. I never use it. If I want
to subvert the type system I find other ways. union does get used
as a hack to find the alignment needed by malloc and friends (a
union of all types will be correctly aligned for, er, all types)
Golden California Girls said:Ben said:We have hit the heart of the disagreement. Where does this come from?
I can't find any support for it in the standard (but I am probably
biased). To cut to the chase, you are saying that:
union u y;
y.i = 42;
any_function(&y.c);
/* y.i now indeterminate? */
yes? I can't get that from the standard. What is your reasoning?
[assuming .i is int and .c is char]
I'm not a standards maven, but K&R2 6.8 p147-8, "it is
implementation-dependent if something is stored as one type and
extracted as another."
any_function hasn't been prototyped, but unless there is const in
it, it has explicitly been given permission to store data to the .c
part. What if anything happens to the rest is
"implementation-dependent".
I know you believe that if any_function does not store into the
union that you expect y.i to be as it was before the function call,
but the standard doesn't say it has to be.
What are you passing to any_function, zero or forty two? Consider
big or little endian before you answer.
Also consider does the
standard care if you swapped .i and .c in your example? Would there
be a discussion in that case?
Golden California Girls said:Ben said:We have hit the heart of the disagreement. Where does this come from?
I can't find any support for it in the standard (but I am probably
biased). To cut to the chase, you are saying that:
union u y;
y.i = 42;
any_function(&y.c);
/* y.i now indeterminate? */
yes? I can't get that from the standard. What is your reasoning?
[assuming .i is int and .c is char]
I'm not a standards maven, but K&R2 6.8 p147-8, "it is
implementation-dependent if something is stored as one type and
extracted as another."
any_function hasn't been prototyped, but unless there is const in
it, it has explicitly been given permission to store data to the .c
part. What if anything happens to the rest is
"implementation-dependent".
I know you believe that if any_function does not store into the
union that you expect y.i to be as it was before the function call,
but the standard doesn't say it has to be.
(I'm sure the standard says something about reading a union member
after storing a different one, but I haven't been able to find it.)
Ben Bacarisse said:Are you thinking of footnote 82 in 6.5.2.3 p3 (which explain what the
value of union.member is)?
If the member used to access the contents of a union object is not
the same as the member last used to store a value in the object,
the appropriate part of the object representation of the value is
reinterpreted as an object representation in the new type as
described in 6.2.6 (a process sometimes called "type
punning"). This might be a trap representation.
There is a change bar in n1256 on the line that references the
footnote, but since I can't justify buying the standard I have no idea
what exactly has changed from the first C99.
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.