Please refer to this site/make edits here for the most updated information:

Parent: MorphoOptimizationProject

Header File Structure

It is desirable to have the headers files form a simple tree

  1. A single header file that defines some widely available commonly used support for bounds checking and similar assertions, malloc et. al, simple math functions (max,min,square,squareroot,abs...). It can include the system-supplied headers that are widely used.
    • This file was missing. I have created one include/base.h

    • The files that were closest to it or widely used - const.h and others - now include it, so it is now included almost everywhere

    • If overrides, such as the optional #define malloc, are included before the system file they wrap, then compilation errors result. The include/base.h includes such header files prior to defining the overriding their functions to avoid this

  2. The various system-supplied header files that are not widely used.
  3. The various third-party header files.
  4. A set of header files defining widely used utilities such as Matrix math. We have this part about right, but there is some near-duplication in areas such as Matrix manipulation because of the history of using third party libraries that had their own definitions
  5. The header files defining our own subsystems
    • These are often put in their own directory rather than having a single include directory, such as we have, to make it easier to associate them with their subsystem

Where to declare variables

When rewriting code to either add parallelism or to understand hot code prior to writing a higher performance version, I have typically changed it from the older style of defining all the variables at the beginning of the function to the style that defines them in the innermost scope possible, and as late as possible in that scope.

The older style was preferable when debuggers did not understand scoped variables, but this does not seem to be an issue any more. There are reliability benefits from placing them closer to where they are initialized and used - not accidently sharing variables (by defining them outside a parallel loop and writing them in the loop), not accidently using uninitialized variables, and making it easier to find all their uses.

Array Bounds

All languages except C - Fortran, C++ via its STL, Ada, and others - make it possible for bounds checking to be automatically generated by compilers. This avoid problems with indexing beyond the ends of the arrays - going one beyond is a classic and difficult to detect problem.

C does not offer this, so functions that are passed array indexs and array indexing where the index might be out of bounds should check the index is in bounds. I have added a chkBnd function to base.h to make this easy to code, and to make it easy to decide whether to generate code for this, or to conditionalize it out.

Dangling and uninitialized pointers

By declaring pointer variables very close to their initialization, it is easier to make sure that they are initialized. The risk is the target will be deleted while the pointer is still live. I have added a freeAndNULL(ptrVariable) macro to base.h to reduce this risk.

MorphoOptimizationProject_codingStyle (last edited 2021-09-22 09:49:00 by DevaniCordero)