Archive for the ‘C++’ Category

Evils of typedefs and legacy code

Monday, September 1st, 2008

Our legacy C++ codebase once was a C codebase.  Way back then, there was no standard boolean type.  So in the wisdom of the day a type was declared

typedef int tBool;

The major problem with tBool’s is that over time enums, #define or magic constants get assigned to them, or they can be compared to said enums, #defines or magic constants, as they are all int’s.

Which works, but years later *somebody* came along and replaced the tBool for bool, and we started getting issues.

Now as in a lot of large codebases there tends to be a large amount of ignored warnings, and not enough daylight hours to remove them all.

So given that, and that your using Visual Studio 2005, here are the ones you should find and remove.

#define NON_BOOL_DEFINE 42
bool boolValue;

boolValue = NON_BOOL_DEFINE;

Warning C4305: ‘=’ : truncation from ‘int’ to ‘bool’

if( boolValue == NON_BOOL_DEFINE )

Warning C4806: ‘==’ : unsafe operation: no value of type ‘bool’ promoted to type ‘int’ can equal the given constant

Another hint your boolean types are being used wrong is this warning

Warning C4800: ‘const int’ : forcing value to bool ‘true’ or ‘false’ (performance warning)

#pragma pack()

Friday, February 22nd, 2008

I have just spent the last hour bashing my head, trying to workout why some new C++ code (to my project) was crashing.

I was constructing one class, and it was building some worker classes and crashing in the std::vector code when the worker class was being destroyed.

It just wasn’t making sense.

Why would code that’s been running for another team for over a year, blow-up when I use it?

I turned to a co-worker, described what was happening and said “it’s like some memory corruption or packing issue

And it was a structure packing alignment issue. The imported project had default packing (8), and my really old solution uses packing (1), so somewhere the default class functions where getting generated with different opinions from where member’s were….

#pragma pack(push)
#pragma pack(4)
#pragma pack(pop)

to the rescue, and low and behold the problems gone. I hate this type of issue. Importing existing C++ projects happens so infrequently that this issue is not on the must check list. Where-as I was convinced I had fluffed up the usage of the new code….

Lint, the best thing for your C/C++ code

Sunday, September 30th, 2007

I was first introduced to PC-Lint at my old company, after complaining about code style and the state of the software after having warnings turned off for years to a co-worker.  I then spent a few months evaluating the software and removing bugs from our system before getting the sign off to purchase licenses for the team.

The best part was finding odd-case errors, fixing them, and later reviewing customer crashes and observing, Oh I’ve fixed that already. Nothing better to say to the management types who love to rush products out the door.

Anyway in our current C++ code base I have been removing large numbers of warnings (and solved some corner case bugs), and now have team buy-in. It’s the most beautiful thing to see the warning count drop, and read check-in comments about warning removal.

On Friday I pulled out the trusty PC-Lint again, but was not sure how best to run this beast of a tool against a Visual Studio project/solution. Enter Visual Lint, a fantastic integration piece of software.

I can see a few more purchase orders in the near future.

Programming Challenges:110502 Reverse and Add

Tuesday, July 31st, 2007

I solved the 110502 Reverse and Add problem today. The hardest part was whipping up the worker functions to do text based numbers.

I started by laying out the algorithm in function blocks, then proceeded to full in the gaps. I had two bugs

  1. my is_palindrome function didn’t have a default return value. It was C++ but even that seems a bit broken, but it compiled!
  2. my data structure could hold 10 digits (ie 1,234,567,890) as the problem stated, but that didn’t seem enough. Size 100 fixed that.

I haven’t done any simple problem work for a while, and I like the idea of doing some of the Rudy Quiz (albeit in C#), yet the testing structure of Programming Challenges site makes it a contained experience.

C++ Default Constructors

Tuesday, May 1st, 2007

Well the bug I was getting bitten by at work is shown by the following code.

class c1
{
public:
int a;
int b;
};

class c2
{
public:
int c;
int d;
c2(): c(3){};
};

class c3
{
public:
int e;
c1 f;
};

class c4
{
public:
int g;
c2 h;
};

int main(int argc, char* argv[])
{
c1 v1;
c2 v2;
c3 v3;
c4 v4;

c1* pv1 = new c1();
c2* pv2 = new c2();
c3* pv3 = new c3();
c4* pv4 = new c4();

return 0;
}

With a break point on the return (in debug mode). Inspection shows the 8 variables have the follow values:

v1 {a=0xcccccccc b=0xcccccccc }
v2 {c=0×00000003 d=0xcccccccc }
v3 {e=0xcccccccc f={a=0xcccccccc b=0xcccccccc } }
v4 {g=0xcccccccc h={c=0×00000003 d=0xcccccccc } }
pv1 {a=0×00000000 b=0×00000000 }
pv2 {c=0×00000003 d=0xcdcdcdcd }
pv3 {e=0×00000000 f={a=0×00000000 b=0×00000000 } }
pv4 {g=0xcdcdcdcd h={c=0×00000003 d=0xcdcdcdcd } }

now v1-v4 are what I’d expect, pv1-pv3 are also are what I’d expect, but pv4 is not!

Because to break the default c3 members values just takes adding a constructor to c1, then c3 is broken.

Both Visual Studio 2003 and Visual Studio 2005 behave the same. It just seems very strange that the existence of a non-default constructor for one member field means that this object (class or struct) doesn’t get a default constructor.

Now I understand the best solution is to never have a struct or class without a constructor, but it just seems so fragile.

The makes extra work for me to upgrade our legacy code base from C malloc to C++ new, as not been able to rely of the default constructor to zero the ram, means I need to manually set all members to zero for all objects.

*GRRR*