Programming Rules - robocortex/openrox GitHub Wiki
Language
OPENROX is written in C99
Standard
OPENROX follows MISRA 2012 coding rules with the following exceptions:
-
When memory is allocated in a function there must exist a single exit point to allow easier memory delete. This can be implemented with a single goto statement, then making an exception to rule 15.1, but following rules 15.2 and 15.3. The label for the goto statement must be
function_terminate
. -
Dynamic memory allocation can be allowed by unsetting the OPENROX_USES_MEMORY_POOL when running the cmake-gui.
Function naming
A function name must be prefixed by rox_
Function structure
-
A function should always return an error code. However, some exceptions are allowed for special functions and low level function. Never return a value or a pointer (Except for very low level functions). If a value/pointer needs to be passed to the calling function, use pointer in the function parameters.
-
A List of error codes is defined in system/errors/errors.h. Please add your own error codes if strongly needed. An error code is an int. A ROX_ERROR_NONE (or 0) is used when there is no error, a positive value when an error occurred.
-
A function is defined as follows
Rox_ErrorCode rox_function_name(Output1, Output2,..., Outputn, Input1, Input2, ... InputN);
The first parameters are read/write (output) parameters, The last parameters are read-only (input) parameters.
-
Each function may be used by various calling functions. Never assume some bounds, validity, etc. on function parameters. In ALL function CHECK parameters. That is : Check pointer nullity, check sizes, check bounds, etc. If, for some optimization reason, you want to avoid those checks, write it in the documentation.
-
The standard structure of a function is the following:
Rox_ErrorCode rox_function_name(Output1, ..., Outputn, Input1, ... InputN)
{
Rox_ErrorCode error = ROX_ERROR_NONE;
// Internal variables and structures declarations and initialisation
Rox_Sint var1 = 0;
Rox_Double var2 = 0.0;
// Internal objects declarations and initialisation
Rox_Object obj1 = NULL;
Rox_Object obj2 = NULL;
// Check Inputs pointers nullity, check sizes, check bounds
// Check Outputs pointers nullity, check sizes
// Internal memory dynamic allocation
error = rox_new(&obj1);
ROX_ERROR_CHECK_TERMINATE( error ) // Check the error and goto return if needed
error = rox_new(&obj2);
ROX_ERROR_CHECK_TERMINATE( error ) // Check the error and goto return if needed
// Processing
error = rox_process1(obj1, var1);
ROX_ERROR_CHECK_TERMINATE( error ) // Check the error and goto return if needed
error = rox_process2(obj2, var2);
ROX_ERROR_CHECK_TERMINATE( error ) // Check the error and goto return if needed
function_terminate: // An unique label per function
// Free dynamically allocated memory
ROX_ERROR_CHECK( rox_del(&obj1); )
ROX_ERROR_CHECK( rox_del(&obj2); )
return error; // An unique return point per function
}
-
The standard label name must be
function_terminate
since the macroROX_ERROR_CHECK_TERMINATE
will goto this label. -
A
rox_xxx_del()
function does nothing if the input pointer is NULL.
Structures
Structures are suffixed with _Struct
:
//! Structure XXX
struct Rox_XXX_Struct
{
//! The integer member a
Rox_Sint a;
//! The real member b
Rox_Real b;
};
Alias to structures are defined using typedef in order to avoid to declare struct Rox_XXX_Struct structname; allowing therefore to declare Rox_XXX_Struct strcutname; directly
typedef struct Rox_XXX_Struct Rox_XXX_Struct;
Pointers to structures are defined using typedef:
typedef struct Rox_XX_Struct * Rox_XXX;
The visibility range of a local variable should be kept as small as possible. Therefore it is better to declare variable used in a loop only directly inside the loop instead that at the beginning of the function.
For your convenience and rox_sdk internal coherence, please use ROX_PI and other macros/defines declared in sources/baseproc/maths/maths_macros.h.
Difference between dynvec and objset
- A dynvec is an array of pointers to "simple" structures (i.e. structures that do NOT contain pointers to dynamically allocated data)
- An objset is an array of pointers to "complex" structures (i.e. structures that contain pointers to allocated data)
Do not create dynvec for complex structures otherwise you will have memory leaks. Indeed, when a dynvec is deleted the allocated data will not be deleted. Instead, when creating an objset we provide the proper "_del" function to delete the allocated data in the complex structure.
For example do not create a dynvec of array2d_double
since the array2d_double
object contains pointers to dynamically allocated data).