Board index » cppbuilder » Re: Any help on why?

Re: Any help on why?


2004-07-08 02:15:17 AM
cppbuilder26
Wayne A. King wrote:
Quote
On Wed, 07 Jul 2004 07:36:44 -0700, Bob Gonder
wrote:

>What if you want to see how a float works?

Then you dump it as raw bytes (chars),
Yeah, you can do that too. But then you'd have endian issues as you
pointed out. The %LX seems to correct endianness.
Quote
not by using a type
specifier in a lib function which is intended for a different type.
I don't really think it was inteded for any "type". It was intended to
convert binary data (of the proper size) into hex.
Quote
The compiler implementors are allowed to assume that the
correct argument type will be passed.
They are allowed to assume that the correct size data will be passed.
What's in that data, they don't care about.
Quote
Since doubles and ints
are different sizes, and different internal layouts, passing doubles
where ints are expected can only lead to unpredictable behavior.
I think it would be predictable. Perhaps surprising to the unwary, but
predictable.
Quote
>%X takes BYTES off the stack and displays them. It doesn't care what
>type they were before they got put on the stack.

Where did you get that notion from? Show me where it says that in
the ISO/ANSI specs for the C/C++ Standard Libraries.
Where else is it going to get it? From Space?
It reads the Byte, Word, Dword, Qword (whatever the prefix calls for),
from the stack and formats it in hex. What's so difficult to
understand about that?
Quote
You're making assumptions about implementation details,
which may vary from compiler to compiler.
I very much doubt %X is going to vary much. It's pretty cut-n-dried.
Quote
You're ignoring
the fact that C and C++ are languages which have extensive
formal specifications. The language specifies what is valid
or invalid.
I don't recall seeing anything that said that you had to pass an INT
and *nothing but* an INT to a %X. Says it takes an int, but it
doesn't say you can't use something else the size of an int.
Quote
You can't arbitrarily use standard library functions
in any way you want (and expect it to work consistently across
implementations/platforms.)
Right, not when sizes are changing all the time. But that's a bug in
the standard (some would call it a feature).
Quote
>Poster could have used %lX for float or double as %X is int, whatever
>size that is (target dependant)..

When l (lower case L) is used with any of these:
d i o u x X
then arg is interpreted as a long int.
On the platform in question, a long int is 32-bits and a double is 64 bits.
Right, should have been %LX
So the OP's printf("%x %x", double1,double2) would have ignored the
double2, printing the first 32bits (LSB) of double1 (which was zero),
then the MSB 32 bits. (Are you still reading, Stan?)
Quote
Further, since floats/doubles are stored with certain bits used for the
mantissa and certain others for the exponent,
There's the words I was looking for! (Got them backwards too...)
Quote
whereas ints are stored
according to the endian architecture of the platform, interpreting a hex
dump of a float (mis)interpreted as an int (or vice versa) would be
challenging to say the least.
I don't see why. Perhaps I'm wrong (again) but when a value is stored,
be it short or long or float, isn't it stored in endian fashion? So a
float or double will be pushed in endian fashion, and %X will read it
in endian fashion, and display it MSB first.
%X seems to take endian into account when converting. Needs to,
doesn't it? I mean, if you take int i=0x1234 you don't want to see
3412 come out of %X.
 
 

Re:Re: Any help on why?

Stan DeGroff wrote:
Quote
BC++ V5.02 Copyright 1997

You've come up with exactly what I think was going on. I've seen other
cases do the same.
printf doesn't seem to invoke code that produces values that stick around
beyond their non-printf use.
I've seen it too, so figured that might be it, but see my post of 10
minutes ago for your real problem.
Quote
When I look at the CPU screen I see that code is optimized. (Even though I
have "no optimization" checked in the project->options screen. Some
statements can't be used as break points as they have been optimized away as
well.)

Is there a way to insure optimization is not invoked?
Not entirely. Best you can do is notice the bug and work around it by
making the value global, or doing something (just about anything) with
it later in the code.
 

Re:Re: Any help on why?

Wayne A. King wrote:
Quote
I wrote
>float pi = 3.1415;
>Looks like 400 is the mantisa
Exponent
Quote
Output (16-bit DOS program, TC++ 3.0 used):
The number 3.141500 is 0.785375 times two to the power of 2
And this tells us what? about the structure of a double?
Does it in any way show that 2^2 is x400?
 

{smallsort}

Re:Re: Any help on why?

Bob Gonder < XXXX@XXXXX.COM >writes:
Quote
Thomas Maeder [TeamB] wrote:

>X and lX are for integral values. Using them for something else is an even
>uglier hack than using the *printf() machinery at all.

And you call the below code *Not* ugly?
The ugliness derives from the problem. In contrary to your code, mine is
at least correct.
Quote
>To peek at the internals of, say, a double, the portable way is to
>treat it as an array of unsigned char, as in
>
>double d(3.11415);
>unsigned char const *const begin(reinterpret_cast<unsigned char *>(&d));
>unsigned char const *const end(begin + sizeof d);
>for (unsigned char const *c = begin; c!=end; ++c)
>printf("%u ",static_cast<unsigned int>(*c));

Yeah, but you want to use hex. You can't see the bits in 123.
Ok, change %u to %hu.
Quote
My BC++ doesn't support 'reinterpret_cast' That's some new-age mumbo
jumbo designed to slow down programmers.
Actually, it was designed to help programmers. The single most important
source of programming errors is incorrect type casts. So let's better
- invent ugly keywords that make us think once more before casting
- make them stand out so that they are easily spotted
Quote
I suppose it's so hard to
type that it encourages programmers to do *anything* (even use the
correct types!) to avoid it.
Spot on. You only do it if you absolutely must.
Quote
Not to mention, the OP's code was C not C++ to begin with.
Irrelevant.
 

Re:Re: Any help on why?

Just pasted your code in. Same result.... (I just pipe the output to a TXT
file, copy & paste)
--------------------------------
GIven an argument: 1.5
The number of arguments is : 1
0 0, 3FF80000
The result returned bu AddDouble() is: 1.5
Given arguments: 1.5 and 2.5
The number of arguments is : 2
0 0, 3FF80000
1 0, 40040000
The result returned by AddDouble() is 4.0
Given arguments: 1.5, 2.5 and 3.5
The number of arguments is : 3
0 0, 3FF80000
1 0, 40040000
2 0, 400C0000
The result returned by AddDouble() is 7.5
Given arguments: 1.5, 2.5, 3.5 and 4.5
The number of arguments is : 4
0 0, 3FF80000
1 0, 40040000
2 0, 400C0000
3 0, 40120000
The result returned by AddDouble() is 12.0
GIven an argument: 1.5
The number of arguments is : 1
0 0, 3FF80000
The result returned bu AddDouble() is: 1.5
Given arguments: 1.5 and 2.5
The number of arguments is : 2
0 0, 3FF80000
1 0, 40040000
The result returned by AddDouble() is 4.0
Given arguments: 1.5, 2.5 and 3.5
The number of arguments is : 3
0 0, 3FF80000
1 0, 40040000
2 0, 400C0000
The result returned by AddDouble() is 7.5
Given arguments: 1.5, 2.5, 3.5 and 4.5
The number of arguments is : 4
0 0, 3FF80000
1 0, 40040000
2 0, 400C0000
3 0, 40120000
The result returned by AddDouble() is 12.0
-----------------------------------
I think the optimize has something to do with it. BUT, this seems to
indicate otherwise.
I would be tempted to say the %X is not mapping the full floating point
number correctly, however,
The "result" value does.
=====================
Ok now, I tried something which does verify that %X does NOT map correctly
on float, infact it messes up the next number as well.
--------
#include <stdio>
main()
{
float x;
float *ptr_x;
x = 1.5;
ptr_x = &x;
printf("%f = %X\n %p, %p\n", x, x, ptr_x, &x);
return 0;
}
----------
result :
1.500000 = 0
3FF80000, 0012FF88
notice that the second "x" didn't print correctly nor did the following
ptr_x.
Now I'll type cast the second "x" as a long integer so they'll map to the
same length:
---------
#include <stdio>
main()
{
float x;
float *ptr_x;
x = 1.5;
ptr_x = &x;
printf("%f = %X\n %p, %p\n", x, (long int) x, ptr_x, &x);
return 0;
}
--------
result:
1.500000 = 1
0012FF88, 0012FF88
Notice the ptr_x found the correct orientation!
the second "x" did not give the hex listing , but we now know Wayne was
RIGHT!
Next, How can we get the hexadecimal format for a float???
I tried using %LX. Here's result:
1.500000 = 3FF8000000000000
0012FF88, 0012FF88
looks closer, except for verifing tha 3FF8 0000 is indead 1.5
Question: In fortran I can map an array of integers on top of an array of
floating point.
This allows me to gain access to the data in multiplt formats. This is done
by using the
"equate" operand.
Is there a similar operation within C ???
"Bob Gonder" < XXXX@XXXXX.COM >wrote in message
Quote
Stan DeGroff wrote:

>for (i=0; i<x; i++){
>xresult = double va_arg(arglist, double);
>result += xresult;
>printf("%d %X, %X\n", i, xresult, result);
>}
>That prints the
>variable "xresult" resulted in printing 0x0000. However the variable
>"result" printed ok. Any ideas why the compiler forgets xresult?

I know this sounds weird, but try this.

for (i=0; i<x; i++){
xresult = double va_arg(arglist, double);
printf("%d %X, %X\n", i, xresult, result);
result += xresult;
}

I think that because xresult isn't needed later, it is optimised away.
If xresult were global, or used later, it would be made "real".
(Apparantly, being inside a printf is being invisible.)
There's a bug in the optimizer.

BTW, which compiler are you using?


 

Re:Re: Any help on why?

Wayne A. King wrote:
Quote
On Wed, 07 Jul 2004 11:15:17 -0700, Bob Gonder wrote:

>The %LX seems to correct endianness.

The L is intended for use with e E f F G and is interpreted as a
long double (80 bits). X is intended for use with integer types only.
My docs (BCB) show LX as uint64. So don't know about "intended".
Also firmly disagree on "integer types only". You can use %X on
ANYTHING that goes on the stack, and has the matching size for the
prefix to X. I can't see Any way for that to mess up.
(Other than the implimentation not supporting LX as TC3/BC3 don't)
The OP is using BC5.02, so maybe it does better.
Quote
You seem determined to persist in approaching the problem
like an assembler programmer: Exploit low level, platform and
implementation-specific features, bit-fiddling, etc.
Then they shouldn't have placed 'cast' and 'union' in the language.
They encourage bit-fiddling.
Which is what C started out as. It's dificult to write operating
systems in C without bit fiddling. Besides, when I (and the OP in
this case) use %X, it is almost always in a debug type situation, when
platform or compiler differences are moot. Results are what count in
those cases, and wasting time making pretty (truly byte-fiddling)
expansive code just to see what's going on in there, especially when
that code is probably going to be deleted after the bug is caught.....
For production code, I use byte-fiddling routines (my asm heritage
makes me prefer not to use the printf family, and since I don't use
floats, it's no big loss to convert for myself). But printf works
fine for quick-and-dirty, where I don't care overly about the output
quality or the speed.
Quote
IMHO, the proper approach is as a disciplined, informed C/C++
programmer attempting to use the language as designed so
that the program works consistently and portably.
Depends I guess, on if you want to use it "as designed" in the 60/70's
or "as designed" in the 90's. I still don't think of C as "designed"
in that manner. Though C++ certainly has gone (too far) down that
path.
 

Re:Re: Any help on why?

Wayne A. King wrote:
Quote
On Wed, 07 Jul 2004 11:34:04 -0700, Bob Gonder wrote:

>And this tells us what?

Isn't it obvious? It tells us what the mantissa and exponent are
of the double 3.1415
Not what the OP wanted to know, though.
 

Re:Re: Any help on why?

Thomas Maeder [TeamB] wrote:
Quote
Bob Gonder < XXXX@XXXXX.COM >writes:

>Thomas Maeder [TeamB] wrote:
>
The ugliness derives from the problem.
"There are no ugly problems, only ugly solutions."
Quote
In contrary to your code, mine is
at least correct.
Not quite, yours is also wrong-endian on Win/Intel.
Quote
>>double d(3.11415);
>>unsigned char const *const begin(reinterpret_cast<unsigned char *>(&d));
>>unsigned char const *const end(begin + sizeof d);
>>for (unsigned char const *c = begin; c!=end; ++c)
Should be c=end-1, c>= begin; --c
Unless &BigEndian is the _last_ byte? Naw...couldn't be...
See? too much to go wrong with your approach, and it isn't endian
safe. Big code begets many little errors. Better to write it short
and sweet and be done with it.
Quote
Actually, it was designed to help programmers.
Real programmers don't need that kind of "help". As in "We're from the
government, and we're here to help you."
Quote
The single most important
source of programming errors is incorrect type casts. So let's better
- invent ugly keywords that make us think once more before casting
Go along with that, but maybe better would be to fire those inept
programmers (or retrain them).
Quote
- make them stand out so that they are easily spotted
And obfuscate the forest with trees.
 

Re:Re: Any help on why?

Stan DeGroff wrote:
Quote
Just pasted your code in. Same result.... (I just pipe the output to a TXT
Yeah, was the 64bit double being read as two 32bit values by each %x.
Quote
I would be tempted to say the %X is not mapping the full floating point
number correctly, however,
The "result" value does.
Not quite, what you see as "result" is actually "xresult" The first 0
is the lower portion of xresult, the second number is the upper
portion.
Quote
Ok now, I tried something which does verify that %X does NOT map correctly
on float, infact it messes up the next number as well.
Yeah, that's what happens when you use the incorrect sizes.
Quote
Next, How can we get the hexadecimal format for a float???
I tried using %LX. Here's result:

1.500000 = 3FF8000000000000
0012FF88, 0012FF88
looks closer, except for verifing tha 3FF8 0000 is indead 1.5
Ok, so BC5.02 supports LX,
That's the right answer.
It also looks like you are using Windows Target, not DOS, as your
floats are 64 bits.
Wayne posted a link on the format in another sub-thread.
Quote
Question: In fortran I can map an array of integers on top of an array of
floating point.
This allows me to gain access to the data in multiplt formats. This is done
by using the
"equate" operand.

Is there a similar operation within C ???
See union.
For 64bit floats:
union {
float f;
INT64 i;
}number;
number.f = 1.23;
printf( "%LI", number.i );
/* warning..going to be really big number */
/* Not going to be 1 or 123. Somewhere around 4 billion billion */
 

Re:Re: Any help on why?

Bob Gonder < XXXX@XXXXX.COM >writes:
Quote
>In contrary to your code, mine is at least correct.

Not quite, yours is also wrong-endian on Win/Intel.
Mine is endianness agnostic.
Quote
>>>double d(3.11415);
>>>unsigned char const *const begin(reinterpret_cast<unsigned char *>(&d));
>>>unsigned char const *const end(begin + sizeof d);
>>>for (unsigned char const *c = begin; c!=end; ++c)

Should be c=end-1, c>= begin; --c
That would have undefined behavior when c is moved to begin-1.
Quote
Go along with that, but maybe better would be to fire those inept
programmers (or retrain them).
After all these things you posted in this thread, I doubt that you are in
a position to ask somebody else to get retrained, I'm afraid.
 

Re:Re: Any help on why?

"Stan DeGroff" < XXXX@XXXXX.COM >writes:
Quote
Question: In fortran I can map an array of integers on top of an array of
floating point.
This allows me to gain access to the data in multiplt formats. This is done
by using the "equate" operand.

Is there a similar operation within C ???
Some programmers suggest using a union for this, but writing to one union
member and then reading from another has undefined behavior in most cases.
In another post, I showed how to cast a pointer to double to a pointer to
unsigned char and treat the double object as an array of unsigned char.
 

Re:Re: Any help on why?

Quote
Question: In fortran I can map an array of integers on
top of an array of floating point. This allows me to gain
access to the data in multiplt formats. This is done
by using the "equate" operand.

Is there a similar operation within C ???
If by "equate" you meant "equivalence" then look at unions. A union
is a way in C for allowing you to use the same block of memory as any
of two or more types.
. Ed
Quote
Stan DeGroff wrote in message
news: XXXX@XXXXX.COM ...
 

Re:Re: Any help on why?

Wayne A. King wrote:
Quote
On Wed, 07 Jul 2004 12:58:52 -0700, Bob Gonder wrote:

>My docs (BCB) show LX as uint64. So don't know about "intended".

BCB is not topical in this particular newsgroup. It's what happens with
BC++ compilers up to 5.02 that's germane. As I recall, the OP is targeting
16-bit embedded systems and no Borland DOS compiler supports the
extended integer types.
The OP reports that LX works for his 5.02 app.
Quote
>Also firmly disagree on "integer types only". You can use %X on
>ANYTHING that goes on the stack, and has the matching size for the
>prefix to X. I can't see Any way for that to mess up.
If the syntax defies the language spec, the compiler writer may do
ANYTHING with it when parsing the source code. This includes ignoring
one or the other of the type specifier(s) or arguments. In the case of %LX,
if not specifically supported as an implementation-specific language
extension, the implementation *may* ignore the L altogether if it's not
appropriate, or apply it in unknown or unpredictable ways.
Now you're going down the other track. Of course you can only use the
_sizes_ that are implimented. But what you pack into that _size_
agument on the stack can be Anything (that fits).
Quote
Again, you're
trying to guess what the compiler implementors are *always* going to do.
If %X applied to a non-integer type is not specifically supported by the
language spec or by a compiler extension, the implementor may freely
and arbitrarily choose to ignore that arg altogether. It's dealer's choice.
I'd like to know _how_ a printf runtime implimentor, who's only input
is a string and an unknown bunch of binary data on the stack, can
distinguish between an apple and an orange. I can see if you tell him
to decode a float, and give him something that bitwise is illegal for
a float, that he will have a fit, but int types have no underlying
format, and X takes all ranges of data (in the supported byte-wise
sizes). How is he going to "know" that I put garbage in my 32bit
parameter? He can't. Why would he care if I did? His job is to hex
those 32 bits. Nothing more, nothing less.
printf ain't type-safe C++, Wayne. It's the wild and wooly world of C.
Quote
>Then they shouldn't have placed 'cast' and 'union' in the language.
>They encourage bit-fiddling.

Which is why many C/C++ language gurus deprecate their use,
Which is why I don't work for so-called gurus.
Quote
>It's dificult to write operating systems in C without bit fiddling.

The OP is just starting to learn the language.
Which is also why you shouldn't lie to him and tell him he _can't_ use
%X on non-ints. Patently, he _can_ (even though you gnash your teeth
at the thought of it), but he needed to get his sizes right.
Quote
I doubt that he will be
writing an OS using C any time soon. ;-)
Point was, C is made for bit-fiddling. If you don't want to
bit-fiddle, use C++ or Java, or just about anything else.
Just don't condem a C programmer for using the language to his benefit
(or should that be bending the langueage to his will?)
Quote
The rationale behind going
to C (and other higher level languages such as PLUS - Programming
Language for Univac/Unisys Systems) when writing OSes was precisely
to make the OS code portable across vendor's hardware offerings. The
more bit ops incorporated, the more portability suffers.
Yep, but you can't do it without the bit-fiddling.
Quote
You're an anachronism. ;-))
And proud of it.
Quote
>Depends I guess, on if you want to use it "as designed" in the 60/70's
>or "as designed" in the 90's.

As designed according to the C90 spec here and elsewhere,
until Borland releases a C compiler which supports the C99
spec. Of course, one is free to use documented and officially
supported features which are an extension to the language.
But even there, trying to use such features in a way which deviates
from their intended functionality is usually ill-advised.
See, there's that 'intended' word again.
I don't see anywhere where the designer's "intentions" are discussed.
The specs say that X decodes an int.
Fine. My belief is that the designer didn't obfuscate the matter by
saying that "X decodes any data whose size is int" because it's too
wordy, and not succinct. So, _I_ think that this usage _was_
intended. And I don't see how it could be otherwise. (see also next)
Quote
>I still don't think of C as "designed" in that manner.

What do you think the ANSI Standard for the C language was
written for, if not as a design specification?
To keep Microsoft in line? It's a _compiler_ spec. It's not a
program spec.(It does tell the programmer what to expect the compiler
to do with his code, but he is free to ignore or {*word*209} the usage if
he can and so chooses.)
Knowing that X takes an int and hexes it, a programmer with a brain
can figure out that placing something on the stack that looks like an
int (has the size of an int), will be decoded to hex (like an int)
Quote
Warning mantissa.c(15): printf: %X requires integral argument (arg 2) in
function main
"Warning" because the programmer _probably_ made an error, but also
"Warning" because the programmer _might_ know what he's doing.
Otherwise, it'd be an "Error".
Quote
printf() and its companion functions (sprintf() and fprintf()) can be
one of the most prolific sources of problems
Yes, they "can" be, as can just about anything else if you don't know
what you're doing.
 

Re:Re: Any help on why?

Wayne A. King wrote:
Quote
On Wed, 07 Jul 2004 12:59:52 -0700, Bob Gonder < XXXX@XXXXX.COM >
wrote:

(1) How to program in C/C++.
(2) Why the variable xreport wasn't displaying when using %X.

The answer to (1) is: follow the Standard and some good texts/advice.
right, but it was C not C++
Quote
The answer to (2) is: he's using the wrong type specifier in the printf().
Wrong Prefix.
Format specifier was correct for the desired output (hex)
 

Re:Re: Any help on why?

Wayne A. King wrote:
Quote
On Wed, 07 Jul 2004 13:45:43 -0700, Bob Gonder < XXXX@XXXXX.COM >
wrote:

>It also looks like you are using Windows Target, not DOS, as your
>floats are 64 bits.

Floats are 32 bits in both DOS (16-bit) and Windows (32-bit).
Doubles are 64 bits in both DOS (16-bit) and Windows (32-bit).
Then why does the compiler (BCB and apparently BC5.02) push 8 bytes
when passing a float?
fld dword ptr[esp]
yep, 32bit float
add esp,FFFFFFF8
make room for 8 bytes
fstp qword ptr[esp]
put 64 bits on the stack!
Maybe all floats are passed as doubles? Everywhere?
Is this Standard?