| Coding Conventions | Index |
There is a fairly large body of code that supports the BrainStem®. The code is written in with the express intention of being highly portable between computers and operating systems. Therefore there are very few machine specifics in the code. We have also tried to make the code as consistent in syntax as possible to make for better readability.
Code Structure
The code is all written in strict ANSI C. We find this to be the most portable choice. The style of coding is an object oriented style that doesn't require any of the STL libraries or runtime issues associated with C++. Most conceptual blocks such as a file or a library are represented by an opaque reference. This reference is typically implemented as a (void *). All routines that manipulate or use the object are passed the object reference as a first argument. This is the same approach used by most C++ implementations where the "this" pointer is hidden as the first parameter on the stack to method calls. Using this structure, we are able to get most of the benefits of using C++ without the overhead.
Most books or resources on writting solid code make some general suggestions that we have tried to strictly adhere to in this code-base.
Naming Conventions
One rule we have tried to strictly enforce is the use of a "a" prefix on all declared types and routines. This helps avoid collisions with definitions on various platforms. An example is the aBool boolean type. In addition, most routines are named with the object first followed by the action or "method". An example is aFile_Open or aStream_ReadLine.
Machine Specifics
Since there are different "best" approaches on each platform for allocating memory, copying a string, or displaying a debug message, there is a file called aOSDefs.h which compartmentalizes all the common actions and macros these specifics for each platform. Using these macros in all coding has no runtime overhead and makes the same code build on all platforms under all compilers. Take a look at this file to see the macros that have been generalized.
Shared Libraries
Shared libraries are used extensively to help manage the code, re-use common functionallity, and reduce overall executable size in the family of BrainStem applications. Each operating system handles library linkage slightly differently and we have come up with the following calling convention to resolve these differences on all our platforms. Take the following library routine definition as an example:
aMYLIB_EXPORT aLIBRETURN aMyLib_Perform(aMyLib myLibRef, int action, aErr* pErr) aMYLIB_TRAP(aMyLibPerform);
This demonstrates several things. First, aMYLIB_EXPORT is a macro for OS versions that need a preamble to declare a routine as shared when building a library. On Windows this can be done using the _cdeclspec macro. On Unix, we use extern to get the same effect.
Next is the aLIBRETURN value. Since some OS versions cannot return an arbitrary return type, we define this macro. The general convention is that the routine returns 0 (or false) to indicate there were no errors and non-zero or true to indicate an error. Errors are always set in either case in the final parameter as an aErr enumeration value.
Moving along, the routine name follows the conventions mentioned above. The library and object is an aMyLib and the action or method "Perform" follows the hyphen.
The first parameter to a library is always the library reference. You can think of this as the "this" pointer from C++. Some OS Versions need a library reference to find a jump table for the routine and this is where this is handled. Other OS Versions may call directly into the shared library code and may use this for library global object storage.
Other parameters are passed based on the routines needs.
The error state is reported as the last parameter. If the user passes NULL, no error state is set.
Finally, some OS versions need a post-declaration trap for library linkage. Many OS versions just macro this away while others use it as the index into a jump table. Macintosh 68K and PalmOS both use this trap.
Coding Style
People will fight religious wars about coding style. There is probably a good argument for or against most styles. Rather than suffer the arguments, here is the style we use in the entire code base:
aErr demoErr = aErrNone; if (a < 3) demoErr = aErrUnknown: if (demoErr == aErrNone) { switch(a) { case 3: printf("val = %s\n", a); break; case 4: { int temp = a / 2; printf("half val = %s\n", temp); } break; } /* switch */ } if (demoErr == aErrNone) { demoErr = aThis_Is_A_Really_Long_Routine_Name(variable1, a, variable3); } if (demoErr == aErrNone) { if ((a > 100) && (threshold > 100) && (anotherboolean)) printf("this is it"); } |