Jump to content
  • entries
    0
  • comments
    0
  • views
    322

A Rational C/C++ Code Notation Convention


xxmikexx

132 views

This is another post copied from elsewhere in the site, put here so I will be able to retrive it easily in the future. I'll edit the post tonight, it's in rough shape ...

 

xxxxxxxxxxxxxxxxxxxx

 

If you read the Gauges&Panels Software Tools thread you will find the beginning of a discussion of coding techniques. In there I basically claimed that maintainability is more important than performance because with proper system design even loose code will perform acceptably. When it doesn't, the correct solution usually is a design change and not clever tight code.

 

Now I want to turn to the subject of notation, which is one of the key aspects of maintainability. At first most of you are going to think that I'm crazy, but a few of you will come to understand what I'm driving at.

 

xxxxxxxxxxxxxxxxxxxxxxx

 

Let's begin with a code fragment taken directly from the AirBoss sources. You will have to forgive the use of xxxx's because without them the forum software would delete the multiple spaces that the xxx's represent ...

 

GBS_Txt2BtnNdx ( xxxxxxxxxxxxxxxxxxxxxxxxxxxx // See if it's a

xxxxxxxxxxxxxx kDevTyp_PovBtn, xxxxxxxxxxxxxxx // hatswitch"button".

xxxxxxxxxxxxxx apszBtnNam,

xxxxxxxxxxxxxx &iBtnNdx,

xxxxxxxxxxxxxx &fHit

xxxxxxxxxxxxxx ) ;

if (fHit)

xx { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // We did get a match

xx *apiDevTyp = kDevTyp_PovBtn; xxxxxxxxxxxxxxxx // so report the

xx *apiBtnNdx = iBtnNdx; xxxxxxxxxxxxxxxxxxxxxxx // device type and

xx break; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // the position of the

xx } xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // button in the array

 

Even when you ignore the xxx stuff it looks like total gibberish, right?

 

xxxxxxxxxxxxxxxxxxxxx

 

The first thing to look at is the call to the GBS_Txt2BtnNdx function, which begins with a function name "header", GBS.

The "GBS" part of the function name means that it is an GameBoss (GBS) function call. (GameBoss is the original name for the AirBoss/GameBoss product pair.) If I wanted to have a different "Txt2BtnNdx" function somewhere else in a different system, I would be able to have both functions coexist in the same program because their headers would be different, thereby guaranteeing function name uniqueness. (Yes, I do know C++ but so what.)

 

If there are more than two arguments to a function call, and if the function is not something standard like a call to memcpy, I spread the arguments of the call over multiple source lines. This means that the eye can quickly see the various arguments.

 

If you look closely at the code you will see that variable names generally take the form of a prefix such as "api" (discussed later below) followed by a stream of three-character name fragments. These three-character fragments have standard meanings:

 

Txt -- text.

Btn -- button.

Ndx -- index.

 

Thus, once you know the notation, the function name GBS_Txt2BtnNdx will be immediately understood to mean "The GameBoss function that translates a text string to a button index." The use of mixed upper and lower case makes the separate name fragments easy to read.

 

Why three-character name fragments? Well, what better way to name this function. If the name were composed in the conventional way, to achieve the same clarity we would have to rename the function to be

 

gameboss_translate_text_to_button_index

 

which certainly is easy to read. However, it takes longer to read than the stylized GBS_Txt2BtnNdx, and it would force all the function arguments and comments way off to the right, probably off the right hand end of the source code editor screen, necessitating scrolling the window to the right just so the arguments and comments can be cleanly formatted.

 

Furthermore, the name fragments approach allows a lot of logic to be expressed on a single source line instead of having that logic uselessly be spread over several source lines. (We make an exception for conditional expressions and function calls because in those cases we want the clarity that one-name-per-line provides.) Also, the eye can take the variable name in at a glance, and since each name fragment has a standard meaning, the overall meaning of the name can be understood at a glance. This may strike you as weird but electrical engineers have the same three-character convention for signal names, and nobody is bothered by this. In fact, they like it because it keeps schematics from being visually dominated by lengthy signal names.

 

xxxxxxxxxxxxxxxxxxxxxxx

 

So now let's consider some of the other standard name fragments. (There are about fifty, I've never counted.)

 

Ndx - Index, as in the index into an array. Runs 0..N

Cnt - Count. Unlike an Ndx, a Cnt runs 1..N

Src - Source, the origin of a move of some kind.

Dst - Destination, the destination of the move.

Dev - Device.

Rpt - Report.

Typ - Type.

Pov - Point of view.

Str - String or structure.

 

and so on. There is no need for me to list them all here because you get the idea, even if you don't like the idea.

 

xxxxxxxxxxxxxxxxxxxxxxx

 

Now let's move on to the subject of name prefixes. Here I've generalized the concept of "Hungarian Notation". In the standard Hungarian Notation a standard string would have a name prefix of "sz" meaning "zero-terminated string", so a typical string name would be

"szName_Of_The_String". In my notation this becomes "szStrNam".

 

So I've kept "sz" as a prefix, and it retains its standard meaning. I also use the standard "i" to mean "integer", as in "iBtnNdx" which means "an integer that represents an index into the buttons array."

 

The idea behind the Hungarian Notation prefixes is that it becomes unnecessary to look at the top of a function listing to see how variables were declared. The prefix says it all, and all that I've done is to expand the set of prefixes to include some conventions of my own.

 

For example, in the code fragment above we find the name "apszBtnNam", which is not standard Hungarian. Well, the "sz" part of it is, but the "ap" part is not. In my extended notation the "a" of "ap" means "argument of the parent function", and the "p" of "ap" means pointer.

 

Thus apszBtnNam means "the parent function argument that is a pointer to the zero-terminated string that designates the name of a button." This is a complicated idea, but apszBtnNam gets the idea across much faster than does the English translation. Not only that, its appearance in the call to GBS_Txt2BtnNdx trivially shows that this argument is being passed to the daughter function without modification.

 

By the way, "Hungarian" is a reference to the prefix notation inventor, a Microsoftie named Charles Szymony. Since nobody can pronounce his last name (he is from Hungary originally), it was decided to call the idea simply the pronouncable "Hungarian Notation" instead of the unpronouceable "Szymony Notation". Presumably everyone at Microsoft knows who "The Hungarian" is. :)

 

xxxxxxxxxxxxxxxxxxxxxxx

 

Now let's consider the variable name "kDevTyp_PovBtn". Here the prefix "k" means compile-time constant. This is just as informative and much less distracting than the industry-standard capital letters "DEVTYP_POVBTN" would be.

 

Finally, here's the difference between an Ndx and a Cnt: for (iBtnNdx=0; iBtnNdx<iMaxBtnCnt; iBtnNdx++)

0 Comments


Recommended Comments

There are no comments to display.

×
×
  • Create New...