Andrew Que Sites list Photos
Projects Contact
Main

January 20, 2009

C Language Gotchas, Part 2

   Here is a C++ gotcha that derailed me for a while the other day. C++ added some fetchers I love, one being pass-by-reference. Not to dive into it too deep (if you're reading this, you likely understand enough C++ to know this), here's an example:
 void someFunction( int & value )
 {
  ++value;
 }
 //...
 
value = 100;
 someFunction( value );
 // value is now 101
   What I find nice about it is when passing around classes. It avoids having to take the address of objects (the & operator) and makes things a little more clear.
   And now, a gotcha.
 class A
 {
   public:
     void put( int newValue )
     {
       value = newValue;
     }

     int get() const
     {
       return value;
     }

   private:
     int value;
 };

 class B
 {
   public:
     B( A a_ )
     : 
       a( a_ )
     {
     }

   void put( int value )
   {
     a.put( value );
   }

   private:
     A & a;
 };

 // ...
 A a;
 B b( a );
 a.put( 50 );
 b.put( 100 );

 cout << a.get() << endl;
   This will compile without error, but I missed something rather important. When buried in thousands of lines of code spanning tens of files, the missing character is really hard to stop.
   The result of this code will print "50" if it doesn't crash. Why? What happened? The mistake is in the constructor for the class B. Notice how class B has a reference to some instance of class A. To the compiler, this is just a pointer that is automatically dereferenced when used. It it required that a reference in a class be initialized in the constructor, which we did. But we didn't pass a reference to the constructor--we passed a temporary copy. B::a is initialized pointing to the copy--likely some location on the stack. The declaration of the constructor should have been:
 B( A & a_ )
 : 
   a( a_ )
 {
 }
   All that was missing was the ampersand to denote that "a_" was a reference to some instance of class A. In my case, class A was fairly complicated and had a standard list member (std::list). When I called functions that manipulated the list, random results happened. Sometimes it crashed the program--other times it did not. Tracing down problems like this is difficult. Even with the most pedantic compiler warnings (which I always have turned on), there was nothing said about this problem. It's hard to say when such this mistake could be valid syntax--taking a reference to temporary value would only be useful for the duration of the constructor. So I could see a compiler warning being globally applicable for such things. But the bottom line is that the mistake was mine--and a hard gotcha it was.

1 comment has been made.

From hef

August 14, 2013 at 5:30 PM

Check out valgrind, I think it can catch that kind of error. Valgrind can get a little noisy though.
   Tear down in Cedar Rapids last Saturday.  Somehow I managed to fit everything into my truck for the trip home.  I didn't doubt I could do it then, but now that it's done with, I don't know how I did it!

January 18, 2009

C Language Gotchas, Part 1

   I've been writing software in C and C++ for more then 12 years and I know the language quite well. I'm going to assume readers of this article are at least mildly proficient in C/C++. For those who are not, you're likely not going to find much useful here!
   Lately, I've been looking for "gotchas" the language allows you to do. We'll start with a classic:
 if ( status = 1 )
   This is an easy mistake to make and the result of this statement is always true. It's an assignment instead of test. The GNU C compiler with all warnings turned on will warn you if you make this statement. The message returned is "warning: suggest parentheses around assignment used as truth value".
   There is a convention I've started to follow that avoids making mistakes like this. Always placing the constant on the left-side of any test. If you do this, the mistake would become:
 if ( 1 = status )
   GNU C will give you the error "lvalue required as left operand of assignment" should you make this mistake and no C compiler would allow this code.
   There are very few times the assignment followed by a test is necessary. Take for instance this code:
 if ( status = SomeFunction() )
   printf( "SomeFunction failed with error code: %i\n", status );
   Say that SomeFunction returns a non-zero error code if the function fails. Doing this all in one line allows "status" to be loaded with the error code so the code in the "if" statement can handle it.
   One of my coding conventions is to try and only do one operation per line. Although you save a line by doing the assignment and test in the "if" statement, you're not gaining anything. The assembly created to do this is going to be the same as if you wrote it long-hand.
 status = SomeFunction();
 if ( status )
    printf( "SomeFunction failed with error code: %i\n", status );
   There is one place where the assign and test can be useful, and that is "while" loops. This is the most common example:
 while ( 0 < ( bytesRead = fread( someFile, buffer, 1sizeof( buffer ) ) )
   Here we are trying to read data from a file in chunks. When there is no more data available, the loop is done. To expand this so it doesn't use an assignment and test in a single line would look like this:
 bytesRead = fread( someFile, buffer, 1sizeof( buffer ) );
 while ( bytesRead )
 {
   ...
   bytesRead = fread( someFile, buffer, 1sizeof( buffer ) );
 }
   That is OK, but in this instance, you really are creating more code by expanding. So in these cases, the single-line assign and test I can live with.
   The above is a simple gotcha and most experienced (even most novice) programmers can easily identify. Here's one that is a little more challenging:
 int data[ 2 ] = { 1020 };
 int * source = data;
 int value;

 value = *source++;
   What is going to happen? Will value be 10 or 11? And what does source point to afterwards, data[ 0 ] or data[ 1 ]? This is a case of operator precedence and even a veteran programmer may have to stop and think. The post-increment operator (++) has higher precedence then the dereference (*), but post-increments always evaluate the proceeding statements before incrementing. This code will work and no compiler complaints are filed against it. An instance where this might happen:
 int * source;
 int * destination;

 //...

 *destination++ = *source++;
If used in a loop, it will copy the contents of "source" into "destination". The dereference happens first, followed by the incrementing of the pointer (not the referenced data).
   Adding parentheses isn't much help in clarifying what happens:
 *( destination++ ) = *( source++ );
   Again, because the increment operator is an evaluate then increment, it is a little unclear what will happen. To be a more clear, split the statement into multiple lines:
  *destination = *source;
  ++destination;
  ++source;
But it gets worse than that:
 value = ++*source++;
   Yes, this is legitimate C. So what is going to happen? Let's add a little more detail to the code.
 int * data[ 2 ] = { 100200 };
 int * source = data;
 int value;

 value = ++*source++;
   Trial will show that "value" end up 101, "data[ 0 ]" will be 101 and "source" will be be the same as "&data[ 1 ]". So what happened? Take a look at these two cases:
 value = ++*source; /* Case A */
 value = *++source; /* Case B */
   In case A, source will be dereferenced then the data incremented. In case B, source will be incremented and then dereferenced. Why this is the case has to do with the fact the the pre-fix increment and dereference are the same priority. Thus, the associativity properties then decide what happens. Both the pre-fix increment and dereference are evaluated right-to-left. In case A, reading from right to left says "dereference 'source' and increment". Case B is then "increment source and dereference".
   Our initial dirty line "value = ++*source++" when read with operator precedence is then "evaluate source and increment source, dereference and increment". Trying to be as clear as possible, this would be the same as:
 /* value = ++*source++ */
 *source = ( *source ) + 1;
 value = *source;
 ++source;
   I would write the code long-hand myself. Again, the resulting assembly is going to be the same because all those operations need to happen. But I am not a big can of incrementing pointers. Instead, I use array subscripts and an index. Lets try and make a simi-useful example out of this mess:
 enum { DATA_SIZE = 100 };
 int * data[ DATA_SIZE ];
 int * source = data;
 int value;
 int count;

 //...

 count = DATA_SIZE;
 value = 0;
 while ( count-- )
   value += ++*source++;
   This is a rather odd summation (value = sum from 1 to DATA_SIZE x_i + 1) function where all data in the array is incremented by 1 and that array is summed into value. Doing this long-hand using pointer increments would look like this:
 enum { DATA_SIZE = 100 };
 int * data[ DATA_SIZE ];
 int * source = data;
 int value;
 int count;

 //...

 count = DATA_SIZE;
 value = 0;
 while ( count )
 {
   *source = ( *source ) + 1;
   value = *source;
   ++source;
   --count;
 }
   Using array subscripts to write this code instead would look this:
 enum { DATA_SIZE = 100 };
 int * data[ DATA_SIZE ];
 int * source = data;
 int value;
 int index;

 //...

 value = 0;
 for ( index = 0; index < DATA_SIZE; ++index )
 {
   source[ index ] += 1;
   value += source[ index ];
 }
   It is my opinion the above is the most clear of the three. Depending on the compiler and CPU architecture, you may suffer a bit of performance loss using this method. In most cases, however, the trade-off isn't significant enough to worry about--and a compiler with optimization will likely figure out how to generate efficient assembly.

January 17, 2009

Good-bye Cedar Rapids!

Steam-pipe burst

Steam-pipe burst

   This morning I started the tear-down and packing for my return to Wisconsin.  I didn't have much when I moved down, so I knew it wouldn't take too long.  I started about 9:00am.  I knew that before noon, I had to go visit the cable company and return the modem, so around 10:00am, I out to do that.  It turns out that my truck door failed to stay closed, popped open and the dome light completely drained the battery.  When I tried to start the truck, nothing--not a single sign of life.  I don't know anyone in the area or at the apartment complex, so getting a jump would be a long-shot--especially since I would need to give my batter some time to build up a charge before a jump would do anything.  There was an auto-parts store just down the road, so I decided to take a walk.  There I bought a decent battery charger.  After plugging it in, I continued the packing operations.
   By 11:00, I had enough charge in the battery to start my truck and after a long wait in line, had the cable modem returned.  The only part of my moving I was unsure about was what to do about the 4x8' of plywood I had build my bench top out of.  However, it ended up working out pretty good.  I placed the bed and all the bedding in my truck first.  I then threw down the plywood, which was almost level with the walls of my truck bed.  It sloped back to the cab slightly, which I was preferable.  Everything else was wrapped in trash bags (it was snowing on and off).  I situated items such that ridged items, such as computer monitors, my air compressor, ext., where on the outside.  Non-ridged items were in the middle.  This way, I could use a try straps to tie everything down.  I even ended up having left over room.
   The drive was not like when I moved in.  My truck needs rear breaks and a new tire in the back.  For this reason, I've been shifting into neutral when I need to stop, as the front breaks can lock up with the back tires still spinning from the engine idle.  I'm not sure when I first noticed this, but it was just an other reason to ride my bike to work.
   Going into down-town Cedar Rapids, the traffic had slowed down to a crawl because a steam pipe at a factory had burst.  Clouds of steam poured across the road, dropping visibility to nil.  It made a crazy sounds, like a hissing jet engine.  I had to stop in the road as I was going through it because I couldn't even see the end of the hood on my truck--and the road at this point curves.  But the wind was high and I wasn't stopped for more then a few seconds before the cloud moved in an other direction.
   The entire drive home was insanely windy.  I could feel my truck oscillating.  Most of the drive, however, I had a tailwind, and that wasnt' bad.  I arrived at the Garage at 8:05pm and had hardly started moving items in when the welcoming party showed up.  It was good to see everyone again, but I sure went to bed tired!

2 comments have been made.

From ERica

January 22, 2009 at 2:10 PM

What an adventure. I found this, and thought it might interest you. http://www.thelocal.se/17070/20090122/

From Andrew Que (http://www.DrQue.net/)

Wisconsin, USA

January 22, 2009 at 3:38 PM

It's a little intrusive when the government can decide what you can and can not name your child. Whoever decided that was a good idea probably needed to be hugged more as a child.

January 16, 2009

Thank You Rockwell

Red   Blue

Red Blue

   Today was the last day of my contract at Rockwell-Collins.  For some people, their last day is mostly slacking off waiting for the end of the day to end.  But I ended up knocking out two bugs--one of which was really nasty--and got closer to taking out a third.  Unfortunately, I had to drop off my keys and laptop at my consulting firm before everyone there left, so I had to quite working before I was fully finished.
   I took the rest of the evening to relax and get some sleep--tomorrow is going to be a busy day!

January 15, 2009

-24F... now it's cold!

Andrew Que, Jan. 13, 2009

Andrew Que, Jan. 13, 2009

   Today I did my coldest bike ride yet: -24°F (-31°C) with winds of 15 MPH.  Have a look at the weather report just before I left the house.  To meet the challenge, I adjusted my suit.  Layer 1: Thermal pants, tee-shirt, socks, wool balaclava.  Layer 2: nylon balaclava, sweat shirt, sweat pants, wool socks.  Layer 3: hooded sweat shirt, denim pants, leather boots.  Layer 4: balaclava with breathing mask, leather jacket, gloves, clear glasses.  My plan was to expose as little of my skin to the air as I could.  I pulled the balaclavas as close to my eyes as I could get the, with the glasses worked in there.  I've done this before, but I have a lot of problems with the glasses fogging up.  So I tried an experiment: I had a dust mask in my tool box that consisted of a plastic shell with an area to insert a filter in the front.  I pulled out the cloth filter and used the plastic shell to cover my nose and mouth.  Over top of this I wore the balaclava with breathing mask.  This kept the plastic dust mask tight against my face.  In theory, this would direct my moisture filled breaths away from my glasses.  It did help some, but I still ended up with condensation on my glasses. 
   The ride was actually quite comfortable considering the temperature.  I was not cold and was sweating under all my layers.  When I made my milk stop, my glasses turned to ice--something about stopping seems to make them fog up faster.  So after I had my milk, I had to clean them off before setting out again.  Even The Gauntlet wasn't bad.  The glasses do help to keep the wind out of my eyes, which haven't figured out that watering up when it's really cold doesn't help. 
   At work (where everything things I'm completely nuts for bicycling into work at 20 below) I was taken out to lunch by the group.  I change at work into "business attire," although I usually leave on the thermal pants as dress pants are ridiculously thin.  At lunch, I didn't bother suiting up because I knew I was going to ride in a car.  I just grabbed a balaclava, my hoodie and coat.  When I stepped outside, I discovered how cold it really was.  Honestly, I wasn't expecting it to feel that cold.  After all, I had ridden my bike in and spent about 20 minutes outside.  But without the layers, the cold bites hard!
   After work--an early day since I don't have much left to do--I suited up again and did the ride home.  It was still -14°F (-25°C), but I had a almost constant headwind.  Still, it wasn't extremely uncomfortable.  Since I didn't dress in front of a mirror before I left, I had failed to cover as much of my face--and so I did have wind attacking a small patch of skin on the left side of my head.  It wasn't too bad, but I wasn't enjoying it.
   The send off lunch was nice.  I invited my recruiter to join us as my boss (who was planning the lunch) was trying to invite everyone I had worked with.  Since she set this job up for me, I found it fitting to invite her.  It was only the third time I ever met her in person. 
   I think I'll end up missing my team and the job.  Nothing like good solid work and a team of people who know what their doing.  It was nice just to be able to come in, pound on some problems and have a few heads to help you work through them.  My team was supportive and receptive--and that was really nice.  I've had to work with a team that had an elitist attitude and that really sucked.  The truth was, I loved the work.  But when you are talked down to any time you have a question, have your work criticized because it wasn't them who wrote it, and your suggestions for improvement ignored or met with extreme resistance, you begin to feel like your not really doing anything.  This job gave me back the confidence in my own abilities.  Furthermore, because of the strict standard the project is governed by, I know that what I do is the right way regardless of the hardheaded resistance my methods met with.  So people really make a difference, and I'm very glad I was working with professionals this time.
   Along with being easy to work with, my team was full of the "how can we fit that" attitude (as opposed to "that's not my fault/problem" attitude).  Some of some of my team were just down right masters at what they did.  It's really shows when someone takes pride in the work they do, and it's nice to get to work with what they have done--if for no other reason then it work and works well--but more because I find myself saying "wow... that's clever" or "that makes what I need to do easy."
   The picture today is me...again...but this time you can see me... three times.  Why did I setup a mix like this?  Try and read into it.  There'll be a quiz. ;)
Manos!

Manos!

   Going into work today, the temperature was somewhere around 0°F (-17°C), but the wind was around 20 MPH, with gusts even higher.  The ride home I ended up with a tail wind when I started, but it was coming at me right from the side by the time I got to the last leg of the trip.  It was -4°F (-20°C) with winds of 16 MPH.  Yet, it wasn't all that bad.  I knew my fingers would end up numb, despite my impressive gloves.  But I had expected my face to get colder, which it didn't.  Because there was blowing snow, I put on my glasses to keep the snow out of my eyes.  The problem is, they fog up pretty easy, and as I got close to home, I had frost I covering most of the lenses.  I couldn't really see much of anything.  I'd like to figure out a solution for that because I think the glasses really help keep my face warm by shielding off the wind.  But I do need to be able to see!
   Tonight I needed to restock milk and decided it would be a good idea to air up the tires on my truck so I could go get some.  Found that a little hard.  It seems I somehow got condensation in my air hose the other night, which was blown into the tire last time I tried to air it up.  This water froze in the valve stem and I couldn't get any air into the tire.  First I thought I'd try and local auto parts shop to see if they had anything.  Swing and a miss--but who knows, it could have been worth the try.  So, I decided I take the tire off my truck, bring it inside to warm up, and then air it up.  So I broke out my trusty car jack and... nothing.  It didn't want to work.  My guess was something inside was frozen.  After all, it's at most -15°F (-26°C) outside.  No problem... brought it inside and baked it in the oven at 170 for a few minutes.  And... it worked.  So back outside, jack up the truck, stick the safety pin in the jack and pop off the tire.  Back inside, set the tired against the wall by the heater and browse the web for a bit.  Several minutes latter, try to air up the tire and bingo--up it goes.  So back outside, put the tire on the truck and try to adjust the jack.  Nothing.  Jack is dead again.  It's resting on the safety pin and it won't raise.  I could just drive forward and pull the truck off the jack, but it's rear wheel drive and the rear wheel is in the air.  Thus, the differential gear just spun the wheel not touching the ground.  I have a few bags of sand in the bed of my truck for weight, so I decided to try and use one as a ramp.  If I could drive up onto a bag of sand, I could pull the jack out.  It proved to be a bit of a pain, but I did finally get that to work.  I spent so much time trying to get the truck off the jack that I forget to torque the lug nuts.  Only after a mile or so down the road did I remember.  I turned off quickly into a gas station and took care of that.
   Anyway, one heck of a work out just to get some milk!
   Last night I decided to do several series of shots, mostly of myself.  This is my hand under blue light.  I ended up liking the shape and texture the light brought out.
Clouded

Clouded

   The picture is me--twice.  The "background" is a closeup on my face under a strong blue light.  It ended up bringing out some serious texture, caused mainly by the hairs of my 12-o'clock-shadow.  It was so gritty and ugly I decided I liked it.  After a set of color, contrast, and sharpness, I added myself again.
   Today when I biked into work, it was -7°F (-22°C) with winds at 20 MPH.  Coming in I thought to myself "this is kind of cold".  The high for the day was forecast to be 3°F (-16°C).  So when I left work and biked home, I thought to myself "this isn't so bad now."  Once I got inside, I checked the weather.  It was -7°F (-22°C).  Don't underestimate the power of suggestion--I thought it was warmer, so it didn't feel as cold.
   Yep--it's the tail light on my bike.  It blinks to help get people's attention.  The previous one of these I owned use to have several modes of blink mode patterns, which I thought was cool--it tended to draw the eye to it more then just a regular period blink.  Who knows though, it might have been a bad thing.  People may have been watching the blink and not their driving.  Anyway, the blinker ended up lasting less then a year and then stopped working completely.  No idea why.  It came in a kit that had a headlight that also blinked.  It was "water proof", but the weather stripping was cheap and made it very difficult to turn the device on and off.  I lost it when I wiped out on some loss gravel... I was in such a hurry to get out of the road I didn't even notice it was gone.  Oh well, it sucked anyway.  I hope these new ones have a better lifespan.  They are getting quite the workout in the cold as it is. :)
   This is the view out my apartment window.  Most of the time, however, I see nothing out the the window--it's usually completely covered.  When I leave for work in the morning, it's dark.  And when I get back, it's usually dark.  Only on the weekend when I don't go home do I actually look out this window.