Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » How is this possible?

Credits go to Bruce Perry and RPG Hacker for helping out!
This thread is locked; no one can reply to it. rss feed Print
How is this possible?
Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Hello all,

I'm having a problem with my ScrollBar class, specifically, the Scroller member that it controls.

Whenever I attempt to change the scroll value and handle position through a click and drag, it fails to remember the value that I am assigning to an anchor variable. The anchor variable "start_percent" is supposed to hold the starting percent so I can get the relative position of the handle compared to where it started off at.

I'm watching this thing in the debugger, and an assignment statement is apparently having zero effect. How is this possible? The variable value remains the same before and after assigning it to a different value, just over one line of code execution.

Here's the mysterious gdb session :

Breakpoint 1, BasicScroller::PrivateHandleEvent (this=0x79cb30, e=...)
    at C:\ctwoplus\progcode\Eagle5GUI_GIT_BitBucket\src\Gui\Scroller.cpp:58
58                  start_percent = scroll_percent;
(gdb) p start_percent
$1 = 0
(gdb) p scroll_percent
$2 = 0.600000024
(gdb) next
[New Thread 9840.0x207c]
90         if (e.type == EAGLE_EVENT_MOUSE_AXES) {
(gdb) p start_percent
$3 = 0
(gdb)

And here's the code that controls the widget's response to an input event :

#SelectExpand
46int BasicScroller::PrivateHandleEvent(EagleEvent e) { 47 int retmsg = DIALOG_OKAY; 48 if (e.type == EAGLE_EVENT_MOUSE_BUTTON_DOWN && e.mouse.button == 1) { 49 int msx = e.mouse.x; 50 int msy = e.mouse.y; 51 if (InnerArea().Contains(msx,msy)) { 52 retmsg |= DIALOG_TAKE_FOCUS; 53 if (scroll_handle_area.Contains(msx,msy)) { 54 EagleLog() << "Scroll handle click detected." << std::endl; 55 mouse_drag_handle = true; 56 start_mouse_x = msx; 57 start_mouse_y = msy;
58 start_percent = scroll_percent;
59 } 60 else { 61 down = true; 62 repeat_elapsed = repeat_previous = 0.0; 63 float percent_to_scroll_by = ((float)length_in_view/total_length)/2.0f; 64 if (horizontal_scroller) { 65 if (msx < scroll_handle_area.X()) { 66 /// Scroll left, by 50% of the view length 67 ScrollBy(-percent_to_scroll_by); 68 repeat_scroll_increment = -length_in_view/2; 69 } 70 else if (msx > scroll_handle_area.BRX()) { 71 /// Scroll right, by 50% of the view length 72 ScrollBy(percent_to_scroll_by); 73 repeat_scroll_increment = length_in_view/2; 74 } 75 } 76 else {/// Vertical scroller 77 if (msy < scroll_handle_area.Y()) { 78 /// Scroll up 79 ScrollBy(-percent_to_scroll_by); 80 repeat_scroll_increment = -length_in_view/2; 81 } 82 else if (msy > scroll_handle_area.BRY()) { 83 ScrollBy(percent_to_scroll_by); 84 repeat_scroll_increment = length_in_view/2; 85 } 86 } 87 } 88 } 89 } 90 if (e.type == EAGLE_EVENT_MOUSE_AXES) { 91 if (mouse_drag_handle) { 92 int msx = e.mouse.x; 93 int msy = e.mouse.y; 94 int dx = msx - start_mouse_x; 95 int dy = msy - start_mouse_y; 96 int delta = horizontal_scroller?dx:dy; 97 int length = 0; 98 if (horizontal_scroller) { 99 length = (scroller_area.W() - scroll_handle_area.W()); 100 } 101 else if (!horizontal_scroller) { 102 length = (scroller_area.H() - scroll_handle_area.H()); 103 } 104 if (length == 0) {length = 1;} 105 float percent = (float)delta/length;
106 SetScrollPercent(start_percent + percent);
107 } 108 } 109 if (e.type == EAGLE_EVENT_MOUSE_BUTTON_UP) { 110 if (e.mouse.button == 1) { 111 down = false; 112 if (mouse_drag_handle) { 113 mouse_drag_handle = false; 114 } 115 } 116 } 117 return retmsg; 118}

The first highlighted line is the ONLY line in ANY of my code that assigns a value to the variable start_percent. The second highlighted line is the ONLY place in ANY of my code that the variable start_percent is referenced.

The problem is, start_percent ALWAYS has the value 0.0f or 1.0f, and I have absolutely no idea why.

Am I going to have to inspect the assembly code to figure this out? I really have no clues what to do about this. Ideas on places to start and techniques to try would be nice. My debugging skills are failing me on this one.

EDIT
I've tried both debug and release configurations, and compiling with both MinGW 4.8.1 and MinGW 5.3.0. Results are the same in every case. This is a real mystery.

Bruce Perry
Member #270
April 2000

Is start_percent definitely a float?

If you're using Visual Studio, assembly language is right there (just open the disassembly window) and you should just make the leap. Although it's always an unwelcome curve ball to have to go through a lot to fix a bug, you do come out of it knowing some assembly language :)

--
Bruce "entheh" Perry [ Web site | DUMB | Set Up Us The Bomb !!! | Balls ]
Programming should be fun. That's why I hate C and C++.
The brxybrytl has you.

RPG Hacker
Member #12,492
January 2011
avatar

What does your class definition look like? I don't suppose the error lies in there?

Are you sure it's not just the debugger printing a wrong value? In other words, is the game behaving badly?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

OMG. :o

Super Face Palm.

{"name":"Triple-facepalm-picard-812.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/a\/bab6ae9ba51f4b71e161b934ba3b2485.jpg","w":980,"h":600,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/a\/bab6ae9ba51f4b71e161b934ba3b2485"}Triple-facepalm-picard-812.jpg

start_percent was declared as an int. I don't know how I didn't catch that. And I was wondering why I was getting super bizarre printf output trying to print an int as a long float.

The bug is gone.

Many credits and thanks to you Bruce.

I can't believe gcc didn't warn me about this at all. I've got -Wall and -Wextra and it didn't warn me about the float to integer assignment at all. :o Nor did it warn me about the silent conversion of int to float in the function call.

Thank you too RPG Hacker. The problem was in the class declaration of start_percent.

RPG Hacker
Member #12,492
January 2011
avatar

That's weird indeed. I would definitely expect it to at least throw a conversion warning in that case.

torhu
Member #2,727
September 2002
avatar

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

RPG Hacker
Member #12,492
January 2011
avatar

That's definitely one of the things I dislike about GCC as compared to MSVC. You have to enable a lot of warnings separately instead of just setting a warning level. Also in my opinion, an implicit cast from a float to an int shouldn't be possible in the first place since you're almost always truncating. I didn't even know this was possible.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

-Wconversion is ridiculous. It warns about going from int to float and widening conversions. I tried -Werror=narrowing but that only warns about initializer list narrowing, which is dumb too.

I swear gcc used to warn about these things. But I can't find the right option to enable those warnings again.

torhu
Member #2,727
September 2002
avatar

It sounds stupid that it wouldn't warn about conversions that will cause dataloss. Maybe you should make a basic test case to see if this actually happening?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

#SelectExpand
1 2class TestClass { 3 4public : 5 6 TestClass() : 7 should_be_a_float_but_im_an_int(0), 8 really_a_float(5.5f) 9 {} 10 11 int should_be_a_float_but_im_an_int; 12 13 float really_a_float; 14 15 void SetIntToFloatValue() { 16 should_be_a_float_but_im_an_int = really_a_float; 17 printf("Int = %d , Float = %5.2f\n" , should_be_a_float_but_im_an_int , really_a_float); 18 } 19 20};

-Wall and -Wextra and -Werror=narrowing don't trigger any warning.

It doesn't say anything unless -Wconversion is used, in which case it says :

Quote:

TestConversion.cpp:20:39: warning: conversion to 'int' from 'float' may alter its value [-Wfloat-conversion]
should_be_a_float_but_im_an_int = really_a_float;

Apparently, in older versions of gcc (4.0.3 at least), -Wextra warned about loss of precision. I don't know what possessed them to remove that.

https://gcc.gnu.org/onlinedocs/gcc-4.0.3/gcc/Warning-Options.html (See -Wextra and "loss of precision")

torhu
Member #2,727
September 2002
avatar

Well, that's stupid. But since you're on Windows, why are you using GCC? Download VS community, it's more or less all of VS for free. Its startup time and HD space requirements are those of a stranded overweight whale the size of two or three whole beaches, but it's nice once it gets going. Basically, there's no competition when it comes to C/C++ IDE's on Windows, that's probably why VS has been getting worse the last 14 years... :'(

https://www.visualstudio.com/products/free-developer-offers-vs

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Because it's much easier to build a shared library with gcc than it is with MSVC. With MSVC I have to mess around with .def files and __declspec __dllexport and such.

Also, I don't really like MSVS as an IDE. It's configuration options are unwieldy and mysterious. It's source navigation is cumbersome. CodeBlocks integrates so well with MinGW I have come to totally prefer it. It's just much easier to work with in my opinion.

At some point I'm going to work on getting my library to build with MSVC, but that's a ways out yet. Not super high on my todo list, but I'm sure I would reach a wider audience that way. Some people just can't live without Visual Studio. :/

torhu
Member #2,727
September 2002
avatar

I haven't made a DLL with VS, but I guess you would only need a macro to declare which symbols in the DLL are public. The configuration options are mostly obvious if you know how the underlying tools work. I'm not sure what the problem with the source navigation is, but then again I haven't used VS much for many years. But the debugger is still superb, I've recently used it for my Qt project ;D

RPG Hacker
Member #12,492
January 2011
avatar

It warns about going from int to float and widening conversions.

That's actually reasonable, though, since you're losing precision here, which means that not all ints can be accurately represented by a float. I'd definitely expect it to warn in this case. As for int -> long long conversions, yeah, it seems a bit unnecessary to warn in such a case.

Neil Roy
Member #2,229
April 2002
avatar

I played with VS a little and I had to admit the debugger was awesome, but... it feels like making a deal with the devil when using it. I can picture Microsoft with fire in the background, an evil laugh and a pitchfork cackling gleefully as I use VS... "we got another one! Muahahahah!" ;D

I did find it a convoluted mess trying to navigate their options.

Anyhow, that is handy to know about -Wconversion, I'll have to add that in as I prefer lots of warnings so I can catch these things.

---
“I love you too.” - last words of Wanda Roy

Bruce Perry
Member #270
April 2000

Neil Roy said:

I did find it a convoluted mess trying to navigate their options.

Yep, for C++ at least, that is definitely a big clusterpork. The whole idea of having its own folder structure which can diverge from the actual folder structure - whyyyyyyy?!

At least with Unity, they match. Not sure about stand-alone C# projects but I have a feeling they match there too.

--
Bruce "entheh" Perry [ Web site | DUMB | Set Up Us The Bomb !!! | Balls ]
Programming should be fun. That's why I hate C and C++.
The brxybrytl has you.

Arvidsson
Member #4,603
May 2004
avatar

The whole idea of having its own folder structure which can diverge from the actual folder structure - whyyyyyyy?!

You don't have to use that, you can view the actual folder structure as well.

VS2015 works great for me, I like it. And with Allegro in nuget I'm no longer stuck in dependency and build hell wooo! :)

Go to: