Dumb compiler or dumb coder?

Started by
20 comments, last by Willm 19 years, 11 months ago
Well a max framerate of 0 doesnt make much sense either. If 0 is supposed to mean there is no limit, then set the framerate to std::numeric_limits::max().
Advertisement
The code does make sense in context, but really whether it does or not is irrelevant. The question is why does the compiler error, the answer is because it uses a bottom up parser which sees the division before the conditional. Compilers don't process things left to right like humans might, which is important because we don't want them pretending that 6 + 6 / 2 is equal to 6, we want it equal to 9.

If there's a compiler bug here, it's that it errors instead of warning. Maybe you can turn that off with a pragma in MSVC?

Edit: Trying to fit everything into one post here:

fredizzimo - It works when MaxFrameRate is not const because then the compiler can no longer make the optimization in the parsing stage, it has no choice but to delay the initialization of FramePeriod until runtime.

[edited by - bobstevens on May 7, 2004 12:05:55 PM]
Aarrrrgggggghhhhhhhh!!!

That''s it! It may not be el-perfecto but do it this way. Or at least some way that compiles.

#define THE_FREAKIN_FRAME_RATE 0

#if THE_FREAKIN_FRAME_RATE > 0
const int MaxFrameRate = THE_FREAKIN_FRAME_RATE;
const double FramePeriod = 1.0 / (double)THE_FREAKIN_FRAME_RATE;
#else
const int MaxFrameRate = 0;
const double FramePeriod = 0.0;
#endif

#undef THE_FREAKIN_FRAME_RATE

R

--------------------------------------------------------------------------
There is no point in flaming if you''ve merely poured fuel on your own head
R--------------------------------------------------------------------------There is no point in flaming if you've merely poured fuel on your own head
Having a value of 0 for the second operand of the operator/ is ''undefined behavior''. The compiler can issue an error message if it wishes, or do anything else that it wants to do. So its not really a bug.
quote:Original post by Jingo
Having a value of 0 for the second operand of the operator/ is 'undefined behavior'. The compiler can issue an error message if it wishes, or do anything else that it wants to do. So its not really a bug.


Fair enough, although this seems in conflict with the IEEE 754 standard for floating point numbers, which says that a positive number divided by zero results in infinity. I mistakenly said that it was NaN earlier.

A useful alternative, although still mildly horrible, could be:
int MaxFrameRate_tmp = 0;const double FramePeriod= MaxFrameRate_tmp > 0 ? 1. / MaxFrameRate_tmp : 0;const int MaxFrameRate = MaxFrameRate_tmp; 


[edited by - bobstevens on May 7, 2004 1:18:13 PM]
There's no need to fall back to macro programming here. You can keep using constants and calculate the double at compile time using templates:

// Some template magic heretemplate<size_t MaxFrameRate>struct FramePeriodCalculator { static const double value; }; template<size_t MaxFrameRate>const double FramePeriodCalculator<MaxFrameRate>::value = 1. / MaxFrameRate; template<> const double FramePeriodCalculator<0>::value = 0.; // Now it works ;-)const size_t MaxFrameRate = 0;const double FramePeriod = FramePeriodCalculator<MaxFrameRate>::value;


-Markus-


[edited by - Cygon on May 7, 2004 1:20:35 PM]
Professional C++ and .NET developer trying to break into indie game development.
Follow my progress: http://blog.nuclex-games.com/ or Twitter - Topics: Ogre3D, Blender, game architecture tips & code snippets.
Cygon beat me to the template solution, that''s the way to do it =)
"Is life so dear, or peace so sweet, as to be purchased at the price of chains and slavery?" - Patrick Henry
quote:Original post by bobstevens

fredizzimo - It works when MaxFrameRate is not const because then the compiler can no longer make the optimization in the parsing stage, it has no choice but to delay the initialization of FramePeriod until runtime.


It doesn't leave anything to runtime when using full optimizations. It generates the following code
	00		 fld	 QWORD PTR __real@0000000000000000  00006	83 ec 08	 sub	 esp, 8  00009	b9 00 00 00 00	 mov	 ecx, OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A  0000e	dd 1c 24	 fstp	 QWORD PTR [esp]  00011	e8 00 00 00 00	 call	 ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@N@Z ; std::basic_ostream >::operator<<  


So obviously the compiler is able to parse the statement. Note there's no comparsions and that I added a std::cout at the end to output the actual value

Why it doesn't use its full parse capabilities when using const is a mystery.

Edit actually that's not even full optimizations, it's just the default optimize for speed, that doesn't do any global optimizations or things like that.

[edited by - fredizzimo on May 7, 2004 2:55:26 PM]
quote:Original post by fredizzimo
Why it doesn''t use its full parse capabilities when using const is a mystery.


No, I don''t think it is. When you declare something as a constant it can make the optimization in the parse tree itself. The compiler is trying to do this with the constant, but since it is zero, there''s an error. But when something isn''t constant it has to make the optimization in a later pass, if at all. MSVC probably has a later pass which discovered that the MaxFrameRate variable couldn''t be anything but 0 given the context, and it made the optimization based on that. Since the optimization was made in a later pass, it took the result of the conditional into consideration and ignored the divide by zero.

quote:Original post by bobstevens
quote:Original post by fredizzimo
Why it doesn''t use its full parse capabilities when using const is a mystery.


No, I don''t think it is. When you declare something as a constant it can make the optimization in the parse tree itself. The compiler is trying to do this with the constant, but since it is zero, there''s an error. But when something isn''t constant it has to make the optimization in a later pass, if at all. MSVC probably has a later pass which discovered that the MaxFrameRate variable couldn''t be anything but 0 given the context, and it made the optimization based on that. Since the optimization was made in a later pass, it took the result of the conditional into consideration and ignored the divide by zero.


You don''t need to explain why it does it. The point is that it detects a divide by zero in an early phase and flags it as an error too early. If the compiler just flagged it as a potential error, and parsed further the error would not happen. Mystery was maybe a too strong word, but since the compiler has a much more advanced parser than that it should make the error happen only when it really is an error, not before.

The compiler is able to detect errors and warning that comes only after full parsing too, like "all code paths doesn''t return a value", and similars. I''m also pretty sure it have given me errors/warnings about divide by zero for non constant values, but only after taking the full codepath into account, which means it''s able to detect the exact same error at a later stage.

Don''t try to defend the compiler writers here, it''s a clear bug. I understand they took it the easy way though, or possibly they didn''t even think about the whole case, but it''s not an unfixable bug. A warning instead of error would be better in this case, but generally I would prefer an error if I make a division by zero. And if it clearly detects that the division by zero never can occour, why give a message at all?

This topic is closed to new replies.

Advertisement