Crazy (?) C problem

J

Jason Sewall

Hello,

I'm using the intel C++ 8.0 compiler on windows and I'm working on some
software that uses the following lines of code:

gf->invdim = 1.0/(double)dim;
printf("invdim: %f\n", (float)gf->invdim);

dim is an integer, gf->invdim a double. I always get "-1.#IND00" as the
output of this code, no matter the value of dim, but only at certain
stages in the code.

If I duplicate the code like so:

gf->invdim = 1.0/(double)dim;
printf("invdim: %f\n", (float)gf->invdim);
gf->invdim = 1.0/(double)dim;
printf("invdim: %f\n", (float)gf->invdim);

The first output is the NAN but the second is the expected result.

I thought I understood C pretty well, but this is weirding me out.

I realize that this is grossly out of context but the program is pretty
complicated and I don't think it would help understand this anyway.

If anyone here has an insight, I'd be much obliged.

Jason Sewall
 
J

Jason Sewall

Sorry, here's a quick followup (very quick, I posted the parent just two
minutes ago).

I compiled it with intel 8.0 in "Release" mode. No problem. (The problem
described in parent occured in intel "debug" mode.

In MSVC 6 Debug, no problem. Ditto for Release.

There must be some sort of bug in my program that only intel debug
exposes, a bug in intel, or some weird debug setting that I don't
understand.

Anyway, your comments are welcome!

Jason
 
M

Martin Ambuhl

Jason said:
Hello,

I'm using the intel C++ 8.0 compiler on windows and I'm working on some
software that uses the following lines of code:

gf->invdim = 1.0/(double)dim;
^^^^^^
pointless cast, the conversion to floating point is triggered by the 1.0
printf("invdim: %f\n", (float)gf->invdim);
^^^^^^^
pointless cast. %f is the specifier for a double
 
I

infobahn

Jason said:
Hello,

I'm using the intel C++ 8.0 compiler on windows and I'm working on some
software that uses the following lines of code:

gf->invdim = 1.0/(double)dim;
printf("invdim: %f\n", (float)gf->invdim);

The cast is pointless. printf will receive the value as a double anyway.
dim is an integer, gf->invdim a double. I always get "-1.#IND00" as the
output of this code, no matter the value of dim, but only at certain
stages in the code.

I can see nothing in the code you posted that would provoke such an
output (unless dim were 0, which I presume you already considered).
If anyone here has an insight, I'd be much obliged.

The problem almost certainly lies elsewhere. I believe that you are
looking at the bomb's landing site, not its launch site. I wouldn't
like to speculate on possible causes without seeing the code.
 
C

CBFalconer

Jason said:
.... snip ...

gf->invdim = 1.0/(double)dim;
printf("invdim: %f\n", (float)gf->invdim);

printf is a variadic function. %f expects a double argument. You
are casting the argument to a float, thus invoking undefined
behaviour. I also see no sign of #include <stdio.h>.

All casts are inherently suspicious.
 
P

Peter Nilsson

CBFalconer said:
printf is a variadic function. %f expects a double argument. You
are casting the argument to a float, thus invoking undefined
behaviour.

Not directly. It's only undefined behaviour if gf->invdim is not
representable as a float. The cast will not stop the implicit promotion
back to double, as per default argument promotions.
 
K

Keith Thompson

CBFalconer said:
printf is a variadic function. %f expects a double argument. You
are casting the argument to a float, thus invoking undefined
behaviour.

But the float is then promoted to double.
I also see no sign of #include <stdio.h>.

Or of a main program (it's just a code snippet). But if
"#include <stdio.h" is missing, you should definitely add it.
All casts are inherently suspicious.

Agreed.
 
J

Jason Sewall

About the explicit double cast; this has no effect on the code, correct?
I prefer an explicit cast where possible to eliminate any confusion.

About the printf formatting: I thought %f expected a float, not a
double, hence the cast.

As for comments about including stdio.h, it has been included outside
the snippet shown here. In fact, there's a whole program around that
snippet of code. I surprised nobody pointed out that there's no
declaration of gf or its members, or dim. In fact, there isn't even a
main() statement!

The sarcasm is simply to point out that I wanted you all to assume that
it had those things that every C program does.

At any rate, the only think I can think of is that I have some
assignment to a void pointer somewhere that's corrupting the data in the
program. Whatever, I'll just use the release mode to get the project
finished. I'll clean up the code later and see if the bug shows up.

On that note, any suggestions on software for testing for memory leaks
on windows?

Thanks,
Jason
 
M

Mike Wahler

Jason Sewall said:
About the explicit double cast;
this has no effect on the code, correct?

It could give incorrect results.
It could slow it down (but probably not noticeably).
I prefer an explicit cast

casting is explicit by definition.
where possible to eliminate any confusion.

Your code can *cause* confusion by giving a wrong answer.
It exposes *your* confusion about how C works.
About the printf formatting: I thought %f expected a float, not a
double, hence the cast.

Back to the books for you! :)

(A good 'rule of thumb' (as Chuck alluded) is:
Treat with suspicion every cast you see and every
inclination you have to cast).

Hmm, I feel a .sig coming on...
"Casts cast suspicion upon the code."

(Sometimes a cast is indeed the only way to do
something, but you should be *certain* you
know what you're doing, and why).
As for comments about including stdio.h, it has been included outside
the snippet shown here.

It's always best to post compilable code if at all possible.
If your code is large, pare it down to a (still compilable)
example that still reproduces the problem you're asking about.
In fact, there's a whole program around that
snippet of code. I surprised nobody pointed out that there's no
declaration of gf or its members, or dim.

This means that answers you get are only educated guesses
and cannot conclusively explain your program's behavior.
In fact, there isn't even a
main() statement!

main() is a function, not a statement. Also, a file
containing compilable C code need not contain a 'main()'
function at all (most nontrivial C programs are composed
of many source files, and only one will contain a 'main()'
function.)
The sarcasm

What sarcasm?
is simply to point out that I wanted you all to assume

Hah!

that
it had those things that every C program does.

A huge number of posts here contain code claimed to
be "C programs" which really are not.
At any rate, the only think I can think of is that I have some
assignment to a void pointer somewhere that's corrupting the data in the
program. Whatever, I'll just use the release mode to get the project
finished. I'll clean up the code later and see if the bug shows up.

Why not actually analyze the problem and really solve it?
Just guessing will often simply dig you deeper into trouble.
Do some testing and use your debugger.
On that note, any suggestions on software for testing for memory leaks
on windows?

Not topical here. Try a Windows group.

Finally, please don't top-post in comp.lang.c

-Mike
 
O

Old Wolf

Jason said:
As for comments about including stdio.h, it has been included
outside the snippet shown here. In fact, there's a whole program
around that snippet of code. I surprised nobody pointed out that
there's no declaration of gf or its members, or dim. In fact,
there isn't even a main() statement!

Nitpick - main() is not a statement (it's a function).
The sarcasm is simply to point out that I wanted you all to
assume that it had those things

To assume makes an ASS out of U and ME. It was quite credible
that your problem was caused by omitting the "#include <stdio.h>"
(because then printf() would have been declared incorrectly, and
you had reported problems with printf's behaviour).
that every C program does.

You'd be surprised how many programs don't have those things.
At any rate, the only think I can think of is that I have some
assignment to a void pointer somewhere that's corrupting the data in the
program. Whatever,

Try posting a compilable program that demonstrates the problem.
I'll just use the release mode to get the project
finished. I'll clean up the code later and see if the bug shows up.

Most likely, it will show up just when you have to demo the code
to someone important.
 
O

Old Wolf

Peter said:
Not directly. It's only undefined behaviour if gf->invdim is not
representable as a float.

It's only undefined if gf->invdim is outside the range of float.
If it is in the range but not representable exactly as float, then
it must be rounded to one of the two nearest values in an I-D manner
(that's how I am reading C99, anyway).

Also, some people have suggested the cast is pointless. It would
be useful if you wanted to investigate what happened when the
double in question is rounded to a float (for example, if you had
noticed strange behaviour when calling a function prototyped
to take a float parameter).
 
K

Keith Thompson

Mike Wahler said:
It could give incorrect results.
It could slow it down (but probably not noticeably).


casting is explicit by definition.


Your code can *cause* confusion by giving a wrong answer.
It exposes *your* confusion about how C works.

That's a little harsh. The original context (lost in the followups)
was:

gf->invdim = 1.0/(double)dim;
printf("invdim: %f\n", (float)gf->invdim);

where dim is an integer and gv->invdim isa double.

The constant 1.0 is of type double (as is any unsuffixed floating
constant), so if the cast is omitted:

1.0/dim

the value of dim will be converted to double. The cast, in this
particular case, is redundant but harmless.

Casts are inherently suspicious because they do too much, and C has
enough implicit conversions that casts are usually unnecessary. In
many cases, a cast tells the compiler "I know what I'm doing; shut up
and doing what I say" -- which is dangerous if you *don't* know what
you're doing. The classic example is casting the result of malloc(),
which can (in C90) mask the error of omitting the "#include <stdlib.h>".

But casts from one numeric type to another are *relatively* harmless,
since they convert the value rather than just copying the bits (as
pointer casts often do).

Casts are like gotos. They have legitimate uses, but their abuse has
caused any use of them to be suspicious.

[...]

And we had no way of knowing that.
It's always best to post compilable code if at all possible.
If your code is large, pare it down to a (still compilable)
example that still reproduces the problem you're asking about.

That's good advice. In fact, in the process of narrowing down your
code to a small compilable snippet, you'll often solve the problem
yourself.

But this case may be one of the rare exceptions. The symptom was
showing up in a 2-line code snippet. Duplicating that snippet changed
the symptoms, which didn't make much sense. It might not have been
possible to narrow down the program while still exhibiting the
problem.

[...]

What do you mean by "assignment to a void pointer"? Do you mean a
null pointer?

Probably something executed before the snippet you showed us invoked
undefined behavior and corrupted something somewhere. There are
numerous things that can cause undefined behavior.

Compile your code with the highest possible warning and optimization
levels (higher optization levels cause the compiler to do more
analysis, which can allow it to detect more errors). Run it under a
debugger. Examine everything you can, including address and values of
variables (gf is a pointer; see what address it points to). If
anything looks odd, trace back in your program and see how it got that
way.
 
M

Mike Wahler

Keith Thompson said:
That's a little harsh.

Perhaps. That wasn't my intention.
The original context (lost in the followups)
was:

gf->invdim = 1.0/(double)dim;
printf("invdim: %f\n", (float)gf->invdim);

where dim is an integer and gv->invdim isa double.

The constant 1.0 is of type double (as is any unsuffixed floating
constant), so if the cast is omitted:

1.0/dim

the value of dim will be converted to double. The cast, in this
particular case, is redundant but harmless.

I was talking about the cast of 'invdim' to 'float'.
Casts are inherently suspicious because they do too much, and C has
enough implicit conversions that casts are usually unnecessary. In
many cases, a cast tells the compiler "I know what I'm doing; shut up
and doing what I say" -- which is dangerous if you *don't* know what
you're doing.

In this case (the cast to 'float') I think that is the case.

The classic example is casting the result of malloc(),
which can (in C90) mask the error of omitting the "#include <stdlib.h>".

But casts from one numeric type to another are *relatively* harmless,
since they convert the value rather than just copying the bits (as
pointer casts often do).

But my point was that casting a double to a float
can lose information.
Casts are like gotos. They have legitimate uses, but their abuse has
caused any use of them to be suspicious.
Yes.


That's good advice. In fact, in the process of narrowing down your
code to a small compilable snippet, you'll often solve the problem
yourself.
Yes.


But this case may be one of the rare exceptions. The symptom was
showing up in a 2-line code snippet. Duplicating that snippet changed
the symptoms, which didn't make much sense. It might not have been
possible to narrow down the program while still exhibiting the
problem.

I was responding to OP's:

"About the printf formatting: I thought %f expected a float, not a
double, hence the cast."



-Mike
 
K

Keith Thompson

Mike Wahler said:
Perhaps. That wasn't my intention.


I was talking about the cast of 'invdim' to 'float'.

Sorry, I missed that; I thought you were talking about (double)dim.

The cast to float is also a numeric-to-numeric cast, so it doesn't
have the same pitfalls that pointer casts can have, but yes, it does
potentially lose information.
 
L

Lawrence Kirby

Sorry, here's a quick followup (very quick, I posted the parent just two
minutes ago).

I compiled it with intel 8.0 in "Release" mode. No problem. (The problem
described in parent occured in intel "debug" mode.

In MSVC 6 Debug, no problem. Ditto for Release.

There must be some sort of bug in my program that only intel debug
exposes, a bug in intel, or some weird debug setting that I don't
understand.

There's nothing obviously wrong in the code you posted. There could easily
be something wrong in the code you haven't posted which ends up affecting
the output of this code. You may alternatively have found a genuine
compiler bug. In order to investigate this further you should create a
minimal program that demonstrates the problem. That should be easy enough
to do by cutting down your existing program until just before the point
where the code works. Hopefully you will then have a program small enough
to post in its entirety.

Lawrence
 

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,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top