structure and union queries

C

CBFalconer

James said:
CBFalconer wrote:
.... snip ...


As the result depends only upon the bits that were stored, and
not upon the format that was used to store them, why would you
need to store that format?

Any union can have an unlimited number of formats, and will only
occupy the space needed for the largest format. So access has to
know the format to be accessed. Conversion needs to know the
format to be converted to. QED.
 
B

Ben Bacarisse

CBFalconer said:
Any union can have an unlimited number of formats, and will only
occupy the space needed for the largest format. So access has to
know the format to be accessed. Conversion needs to know the
format to be converted to. QED.

You have snipped so much all the context is lost. Are you still
thinking that the OP expected conversion rather than reinterpretation?
James was quite clear in his reply that the OP was talking about the
usual reinterpretation that happens with a union and not a conversion
from the type last stored to the type that is later accessed.

The format (as you call it) is know to the compiler when a union
member is written or read, so no format needs to be stored to
implement the reinterpretation semantics required by C.
 
C

CBFalconer

Ben said:
You have snipped so much all the context is lost. Are you still
thinking that the OP expected conversion rather than
reinterpretation? James was quite clear in his reply that the OP
was talking about the usual reinterpretation that happens with a
union and not a conversion from the type last stored to the type
that is later accessed.

The format (as you call it) is know to the compiler when a union
member is written or read, so no format needs to be stored to
implement the reinterpretation semantics required by C.

When the bit pattern is different, what is the difference between
conversion and reinterpretation? And, while the compiler may know
when union u has format f written into it, the code that reads from
u is reading a specific format. The compiler, when generating that
code, has no idea what was last written into it.

#include <all needed>

union un {
char ch;
int i;
float d;
} u;

void setval(int val) {
switch 3 * rand() / RAND_MAX { /* returning 0 thru 2 */
case 0: u.ch = val;
case 1: u.i = val;
case 2: u.d = val;
default: puts("error");
}
}

int main(void) {
int ct = 0;

for (ct = 0; ct < 10; ct++) {
setval(ct);
printf("%c %d %f\n", u.ch, u.i, u.d);
}
return 0;
}

Please explain how the extraction code (u.i for example) knows what
conversions to apply? Please ignore silly coding errors.
 
B

Ben Bacarisse

CBFalconer said:
When the bit pattern is different, what is the difference between
conversion and reinterpretation?

Given

union { float f; int i; } u; u.f = 66;

then u.i is reinterpretation and (int)u.f is (what I mean by)
conversion. Conversion requires knowledge of the last stored member,
reinterpretation does not. That is why I though you were talking
about conversions.
And, while the compiler may know
when union u has format f written into it, the code that reads from
u is reading a specific format. The compiler, when generating that
code, has no idea what was last written into it.

Yes, that is why the standard says that the bits are reinterpreted as
a (possibly invalid) value of the type being read. I am sure you know
this. I (and James) are just wondering what point you are making.
The OP knows the second retrieved value will be "garbage" (their word)
but they did not know the result could be an invalid (trap) value. I
don't think they ever expected a conversion to the new type to happen.
#include <all needed>

union un {
char ch;
int i;
float d;
} u;

void setval(int val) {
switch 3 * rand() / RAND_MAX { /* returning 0 thru 2 */
case 0: u.ch = val;
case 1: u.i = val;
case 2: u.d = val;
default: puts("error");
}
}

int main(void) {
int ct = 0;

for (ct = 0; ct < 10; ct++) {
setval(ct);
printf("%c %d %f\n", u.ch, u.i, u.d);
}
return 0;
}

Please explain how the extraction code (u.i for example) knows what
conversions to apply?

It does not. As far as I can tell, you complicated the discussion by
suggesting that someone was expecting a conversion when no one was. I
think James was just pointing out that no one expected the Span^H^H^H^H
a conversion to take place.
Please ignore silly coding errors.

Unfortunately, one of them means that in your example, we always know
that last member written, but that is incidental to the issue.
 
J

James Kuyper

CBFalconer said:
When the bit pattern is different, what is the difference between
conversion and reinterpretation?

I don't know what you're referring to when you say "the bit pattern is
different". I can tell you what the difference between conversion and
reinterpretation is. Conversion of a float value of 66.0F to an int
results in an int value of 66. Reinterpretation of bits representing a
float value of 66.0F as bits representing an int will, in general,
generate an implementation-depended result that might be a trap
representation (the key point that the OP seemed unaware of), that
depends upon the representation used for float and int, and will
generally be a number other than 66. In the OP's case, reinterpretation
led to an int result of 1115947008. The OP knew this was a plausible
outcome, and was not surprised by it. He might even know enough about
the representations used for float and int on his machine to predict
that result, though he said nothing to confirm that possibility.
... And, while the compiler may know
when union u has format f written into it, the code that reads from
u is reading a specific format. The compiler, when generating that
code, has no idea what was last written into it.

That's correct, and the OP seemed quite well aware of that fact. If he
were not, he might have expressed surprise at getting a u.i value of
1115947008 after storing a value of 66.0 in u.f. He expressed no such
surprise, and every message you've posted since that time seems to be
based upon the misconception that he was surprised by it. Are you in
fact aware of the fact that he was not surprised by it? That he wasn't
asking why he got that result, because it was the result he expected to get?
#include <all needed>

union un {
char ch;
int i;
float d;
} u;

void setval(int val) {
switch 3 * rand() / RAND_MAX { /* returning 0 thru 2 */
case 0: u.ch = val;
case 1: u.i = val;
case 2: u.d = val;
default: puts("error");
}
}

int main(void) {
int ct = 0;

for (ct = 0; ct < 10; ct++) {
setval(ct);
printf("%c %d %f\n", u.ch, u.i, u.d);
}
return 0;
}

Please explain how the extraction code (u.i for example) knows what
conversions to apply? Please ignore silly coding errors.

It's not supposed to apply any conversions, so that makes the decision
easy: it just takes the bits stored in u.ch, and interprets them as a
char. It takes the bits stored in u.i, and interprets them as an int. It
takes the bits stored in u.d, and interprets them as a float. There's
not a single conversion anywhere in that process.
 
C

CBFalconer

pete said:
Another way of putting that is that there is no such thing as
reinterpretation when the bit pattern is different.

In other words, one form of conversion is the identity relation.
 
C

CBFalconer

Ben said:
Given

union { float f; int i; } u; u.f = 66;

then u.i is reinterpretation and (int)u.f is (what I mean by)
conversion. Conversion requires knowledge of the last stored member,
reinterpretation does not. That is why I though you were talking
about conversions.


Yes, that is why the standard says that the bits are reinterpreted as
a (possibly invalid) value of the type being read. I am sure you know
this. I (and James) are just wondering what point you are making.
The OP knows the second retrieved value will be "garbage" (their word)
but they did not know the result could be an invalid (trap) value. I
don't think they ever expected a conversion to the new type to happen.

So am I (wondering) at this point.
It does not. As far as I can tell, you complicated the discussion by
suggesting that someone was expecting a conversion when no one was. I
think James was just pointing out that no one expected the Span^H^H^H^H
a conversion to take place.


Unfortunately, one of them means that in your example, we always know
that last member written, but that is incidental to the issue.

Oh? Are you claiming that you can back up and find the previous
value emitted by rand? I don't think that is guaranteed.
 
C

CBFalconer

James said:
CBFalconer wrote:
.... snip ...


It's not supposed to apply any conversions, so that makes the
decision easy: it just takes the bits stored in u.ch, and
interprets them as a char. It takes the bits stored in u.i, and
interprets them as an int. It takes the bits stored in u.d, and
interprets them as a float. There's not a single conversion
anywhere in that process.

As usual I have not been sufficiently specific. Imagine some sort
of cast in each printf item, possibly implemented by a routine.
i.e.:

printf("%c %d %f\n", cnvt(u.ch), cnvt(u.i), cnvt(u.d));
 
F

Flash Gordon

CBFalconer said:
Oh? Are you claiming that you can back up and find the previous
value emitted by rand? I don't think that is guaranteed.

Wrong, it is guaranteed.

The description of srand includes the following which explicitly
guarantees that you can:

| The srand function uses the argument as a seed for a new sequence of
| pseudo-random numbers to be returned by subsequent calls torand. If
| srand is then called with the same seed value, the sequence of
| pseudo-random numbers shall be repeated. If rand is called before
| any calls to srand have been made, the same sequence shall be
| generated as when srand is ï¬rst called with a seed value of 1.
 
K

Keith Thompson

Flash Gordon said:
CBFalconer wrote: [...]
Oh? Are you claiming that you can back up and find the previous
value emitted by rand? I don't think that is guaranteed.

Wrong, it is guaranteed.

The description of srand includes the following which explicitly
guarantees that you can:

| The srand function uses the argument as a seed for a new sequence of
| pseudo-random numbers to be returned by subsequent calls torand. If
| srand is then called with the same seed value, the sequence of
| pseudo-random numbers shall be repeated. If rand is called before
| any calls to srand have been made, the same sequence shall be
| generated as when srand is Þrst called with a seed value of 1.

Yes, that means you can recover the previous value returned by rand()
*if* you've remembered the original value passed to srand() and the
number of times rand() has been called since then. But then you might
as well just remember the previous value returned by rand().
 
F

Flash Gordon

Richard said:
Keith Thompson said:
Flash Gordon said:
CBFalconer wrote: [...]
Oh? Are you claiming that you can back up and find the previous
value emitted by rand? I don't think that is guaranteed.
Wrong, it is guaranteed.

The description of srand includes the following which explicitly
guarantees that you can:

| The srand function uses the argument as a seed for a new sequence of
| pseudo-random numbers to be returned by subsequent calls torand. If
| srand is then called with the same seed value, the sequence of
| pseudo-random numbers shall be repeated. If rand is called before
| any calls to srand have been made, the same sequence shall be
| generated as when srand is ï¬rst called with a seed value of 1.
Yes, that means you can recover the previous value returned by rand()
*if* you've remembered the original value passed to srand() and the
number of times rand() has been called since then. But then you might
as well just remember the previous value returned by rand().

It's not the same at all is it? Since you cant get the seed from the
rand() can you? And without that you can not repeat the sequence.

<snip>

In this instance you can get the starting point by reading the code,
since the code in question did not call srand at all and as it was a
complete program this makes it entirely predictable.
 
J

James Kuyper

CBFalconer said:
As usual I have not been sufficiently specific. Imagine some sort
of cast in each printf item, possibly implemented by a routine.
i.e.:

printf("%c %d %f\n", cnvt(u.ch), cnvt(u.i), cnvt(u.d));

%c requires an argument whose promoted type is char, %d requires one
that is compatible with int, %f requires one that is compatible with
float. If cnvt() were an ordinary function, it could only have one
return type, and no single type meets all of those requirements, so the
printf() call would have undefined behavior. If it's a function-like
macro or a <tgmath.h> - like function, then it could produce a result of
an acceptable type.

If it is a <tgmath.h>-like function, I can tell you that cnvt(u.ch) will
receive the value represented by the bits in u.ch, interpreted as a
char. cnvt(u.i) will receive the value represented by the bits in u.i,
interpreted as an int. cnvt(u.f) will receive the value represented by
the bits in u.f, interpreted as a float. If cnvt() is a function-like
macro, it's much harder to say anything meaningful about such code
without knowing precisely what cnvt() is.

I'm very unclear as the function and purpose of cnvt(). You describe the
behavior of cnvt as "some sort of cast", which is peculiar, since each
argument already has an appropriate type for the corresponding format
specifier. It would seem that the only useful purpose for involving
cnvt() would be if it returned a value different from that of it's
argument, which would only be the case for a cast if it were a cast to a
type of lower rank or a different signedness. But what would be the
point of doing that? I'm afraid I'm still at a loss as to what it is
you're trying to say.

Again, it looks like you think your arguing against an expectation or a
suggestion that all three print formats should print the same value. But
this is a suggestion that no one has made, and an expectation that no
one has expressed. Are you in fact aware of the fact that no one has
suggested any such thing?
 
B

Ben Bacarisse

CBFalconer said:
Oh? Are you claiming that you can back up and find the previous
value emitted by rand? I don't think that is guaranteed.

The sub-thread on the reversibility of rand is interesting but not
what I meant at all. There are enough problems with the code that any
guess as to the intent could be flawed, but taking your comment that 3
* rand() / RAND_MAX returns "0 thru 2" as the intent, then the
compiler always knows that u.d is the last member written regardless
of the return from rand() because the cases all "fall through".

Yes, I know this involves fixing some things and ignoring other,
equally probable, mistakes. It just seemed ironic that one of the
things I was being asked to ignore was a coding error that rendered
the whole example pointless.
 
C

CBFalconer

Ben said:
.... snip ...


The sub-thread on the reversibility of rand is interesting but not
what I meant at all. There are enough problems with the code that any
guess as to the intent could be flawed, but taking your comment that 3
* rand() / RAND_MAX returns "0 thru 2" as the intent, then the
compiler always knows that u.d is the last member written regardless
of the return from rand() because the cases all "fall through".

Yes, I know this involves fixing some things and ignoring other,
equally probable, mistakes. It just seemed ironic that one of the
things I was being asked to ignore was a coding error that rendered
the whole example pointless.

Well, all I wanted was some sort of non-backtraceable means of
selecting the form stored, so as to demonstrate the need to know
that form to read the value back from the union. Whew. That was
why I said ignore the errors.
 
C

CBFalconer

Richard said:
You mean "int".

Good point. I had missed that. I guess I very rarely use printf
for chars, and if I do they probably came from an int anyhow.
 
J

James Kuyper

Richard said:
You mean "int".

Actually, what I meant was "the same as the promoted type of char",
which is the same as "int", but had I remembered to address that issue,
I would have wanted to emphasize what the general rule was.
 
B

Ben Bacarisse

James Kuyper said:
Actually, what I meant was "the same as the promoted type of char",
which is the same as "int", but had I remembered to address that
issue, I would have wanted to emphasize what the general rule was.

I have two nits. One may be a defect in the standard.

Nit the first: the promoted type of char can be unsigned int on some
odd implementations.

Nit the second: Richard is correct. %c requires an int argument. It
says so in the specification for fprintf. I had expected the wording
to be yours "the promoted type of char" or some such but it is not.
 

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

Similar Threads

union, strcpy and main() 10
Union and strict aliasing 4
union 7
union 16
[union] Pointers to inherited structs are valid ? 104
Union trouble 7
union member 8
C doubt- union 5

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top