Mahonri List Of Rules For Writing Maintainable C Code



  1. A function shall have only one return.
  2. Returns from nested code can add significant complexity.

  3. The goto statement shall be used to handle exceptions and early-exit conditions.
  4. This rule along with the previous rule, helps to ensure that cleanup (or final statements) are executed.

  5. All functions return an int value; indicating success (0) or error.
  6. Preferably, error values returned are selected from those in errno.h.

  7. Place constants on the left of equality comparisons. [EXP21-C]
  8. "'Yoda conditions' are when you put the condition backwards" --Paul Griffiths/SO

  9. Do not create a universal character name through concatenation. [PRE30-C]]
  10. Avoid side effects in arguments to unsafe macros [PRE31-C]
  11. Do not use preprocessor directives in invocations of function-like macros. [PRE32-C]
  12. Declare objects with appropriate storage durations. [DCL30-C]
  13. Declare identifiers before using them. [DCL31-C]
  14. Do not declare an identifier with conflicting linkage classification. [DCL36-C]
  15. Do not declare or define a reserved identifier. [DCL37-C]
  16. Use the correct syntax when declaring a flexible array member. [DCL38-C]
  17. Avoid information leakage in structure padding. [DCL39-C]
  18. Do not create incompatible declarations of the same function or object. [DCL40-C]
  19. Do not declare variables inside a switch statement before the first case label. [DCL41-C]
  20. Do not depend on the order of evaluation for side effects. [EXP30-C]
  21. Do not access a volatile object through a nonvolatile reference. [EXP32-C]
  22. Do not read uninitialized memory. [EXP33-C]
  23. Do not dereference null pointers. [EXP34-C]
  24. Do not modify objects with temporary lifetime. [EXP35-C]
  25. Do not cast pointers into more strictly aligned pointer types. [EXP36-C]
  26. Call functions with the correct number and type of arguments. [EXP37-C]
  27. Do not access a variable through a pointer of an incompatible type. [EXP39-C]
  28. Do not modify constant objects. [EXP40-C]
  29. Do not compare padding data. [EXP42-C]
  30. Avoid undefined behavior when using restrict-qualified pointers. [EXP43-C]
  31. Do not rely on side effects in operands to sizeof, _Alignof, or _Generic. [EXP44-C]
  32. Do not perform assignments in selection statements. [EXP45-C]
  33. Ensure that unsigned integer operations do not wrap [INT30-C]
  34. Ensure that integer conversions do not result in lost or misinterpreted data [INT31-C]
  35. Ensure that operations on signed integers do not result in overflow [INT32-C]
  36. Ensure that division and remainder operations do not result in divide-by-zero errors [INT33-C]
  37. Do not shift an expression by a negative number of bits or by greater than or equal to the number of bits that exist in the operand [INT34-C]
  38. Use correct integer precisions [INT35-C]
  39. Converting a pointer to integer or integer to pointer [INT36-C]
  40. Do not use floating-point variables as loop counters [FLP30-C]
  41. Prevent or detect domain and range errors in math functions [FLP32-C]
  42. Ensure that floating-point conversions are within range of the new type [FLP34-C]
  43. Preserve precision when converting integral values to floating-point type [FLP36-C]
  44. Do not form or use out-of-bounds pointers or array subscripts [ARR30-C]
  45. Ensure size arguments for variable length arrays are in a valid range [ARR32-C]
  46. Do not subtract or compare two pointers that do not refer to the same array [ARR36-C]
  47. Do not add or subtract an integer to a pointer to a non-array object [ARR37-C]
  48. Guarantee that library functions do not form invalid pointers [ARR38-C]
  49. Do not add or subtract a scaled integer to a pointer [ARR39-C]
  50. Do not attempt to modify string literals [STR30-C]
  51. Guarantee that storage for strings has sufficient space for character data and the null terminator [STR31-C]
  52. Do not pass a non-null-terminated character sequence to a library function that expects a string [STR32-C]
  53. Cast characters to unsigned char before converting to larger integer sizes [STR34-C]
  54. Arguments to character-handling functions must be representable as an unsigned char [STR37-C]
  55. Do not confuse narrow and wide character strings and functions [STR38-C]
  56. Set errno to zero before calling a library function known to set errno, and check errno only after the function returns a value indicating failure [ERR30-C]
  57. Do not rely on indeterminate values of errno [ERR32-C]
  58. Detect and handle standard library errors [ERR33-C]
  59. Clean up thread-specific storage [CON30-C]
  60. Do not destroy a mutex while it is locked [CON31-C]
  61. Prevent data races when accessing bit-fields from multiple threads [CON32-C]
  62. Avoid race conditions when using library functions [CON33-C]
  63. Declare objects shared between threads with appropriate storage durations [CON34-C]
  64. Avoid deadlock by locking in a predefined order [CON35-C]
  65. Wrap functions that can spuriously wake up in a loop [CON36-C]
  66. Do not call signal() in a multithreaded program [CON37-C]
  67. Preserve thread safety and liveness when using condition variables [CON38-C]
  68. Do not join or detach a thread that was previously joined or detached [CON39-C]
  69. Do not refer to an atomic variable twice in an expression [CON40-C]
  70. Wrap functions that can fail spuriously in a loop [CON41-C]
  71. Do not use the rand() function for generating pseudorandom numbers [MSC30-C]
  72. Properly seed pseudorandom number generators [MSC32-C]
  73. Do not pass invalid data to the asctime() function [MSC33-C]
  74. Ensure that control never reaches the end of a non-void function [MSC37-C]
  75. Do not treat a predefined identifier as an object if it might only be implemented as a macro [MSC38-C]
  76. Do not call va_arg() on a va_list that has an indeterminate value [MSC39-C]
  77. Do not violate constraints [MSC40-C]
  78. Use the readlink() function properly [POS30-C]
  79. Do not use vfork() [POS33-C]
  80. Do not call putenv() with a pointer to an automatic variable as the argument [POS34-C]
  81. Avoid race conditions while checking for the existence of a symbolic link [POS35-C]
  82. Observe correct revocation order while relinquishing privileges [POS36-C]
  83. Ensure that privilege relinquishment is successful [POS37-C]
  84. Beware of race conditions when using fork and file descriptors [POS38-C]
  85. Use the correct byte ordering when transferring data between systems [POS39-C]
  86. Do not use signals to terminate threads [POS44-C]
  87. Do not use threads that can be canceled asynchronously [POS47-C]
  88. Do not unlock or destroy another POSIX thread's mutex [POS48-C]
  89. When data must be accessed by multiple threads, provide a mutex and guarantee no adjacent data is also accessed [POS49-C]
  90. Declare objects shared between POSIX threads with appropriate storage durations [POS50-C]
  91. Avoid deadlock with POSIX threads by locking in predefined order [POS51-C]
  92. Do not perform operations that can block while holding a POSIX lock [POS52-C]
  93. Do not use more than one mutex for concurrent waiting operations on a condition variable [POS53-C]
  94. Detect and handle POSIX library errors [POS54-C]
  95. Properly pair allocation and deallocation functions [WIN30-C]


  1. Prefer inlineC99 or static functions to function-like macros. [PRE00-C]
  2. Use parentheses within macros and around parameter names. Parenthesize all parameter names found in macro definitions. [PRE01-C]
  3. Macro replacement lists should be parenthesized to protect any lower-precedence operators from the surrounding expression. [PRE02-C]
  4. Prefer type definitions (typedef) to macro definitions (#define) when encoding types. [PRE03-C]
  5. Do not reuse a standard header file name. [PRE04-C]
  6. Understand macro replacement when concatenating tokens or performing stringification. [PRE05-C]
  7. Enclose header files in an inclusion guard. [PRE06-C]
  8. Avoid using repeated question marks. [PRE07-C]
  9. Guarantee that header file names are unique. [PRE08-C]
  10. Do not replace secure functions with deprecated or obsolescent functions. [PRE09-C]
  11. Wrap multistatment macros in a do-while loop. [PRE10-C]
  12. Wrap multistatment macros in a do-while loop. [PRE10-C]
  13. Do not conclude macro definitions with a semicolon. [PRE11-C]
  14. Do not define unsafe macros. [PRE12-C]
  15. Use the Standard predefined macros to test for versions and features. [PRE13-C]
  16. 'const'-qualify immutable objects. [DCL00-C]
  17. Do not reuse variable names in subscopes. [DCL01-C]
  18. Use visually distinct identifiers. [DCL02-C]
  19. Use a static assertion to test the value of a constant expression. [DCL03-C]
  20. Do not declare more than one variable per declaration. [DCL04-C]
  21. Use typedefs of non-pointer types only. [DCL05-C]
  22. Use meaningful symbolic constants to represent literal values in program logic. [DCL06-C]
  23. Include the appropriate type information in function declarators. [DCL07-C]
  24. Properly encode relationships in constant definitions. [DCL08-C]
  25. Declare functions that return an errno error code with a return type of errno_t. [DCL09-C]
  26. Maintain the contract between the writer and caller of variadic functions. [DCL10-C]
  27. Understand the type issues associated with variadic functions. [DCL11-C]
  28. Implement abstract data types using opaque types. [DCL12-C]
  29. Declare function parameters tha are pointers to values not changed by the function as 'const'. [DCL13-C]
  30. Declare file-scope objects or functions that do not need external linkage as 'static'. [DCL15-C]
  31. Use "L," not "l," to indicate a long value. [DCL16-C]
  32. Beware of miscompiled volatile-qualified variables. [DCL17-C]
  33. Do not begin integer constants with 0 when specifying a decimal value. [DCL18-C]
  34. Minimize the scope of variables and functions. [DCL19-C]
  35. Explicitly specify void when a function accepts no arguments. [DCL20-C]
  36. Understand the storage of compound literals. [DCL21-C]
  37. Use volatile for data that cannot be cached. [DCL22-C]
  38. Guarantee that mutually visible identifiers are unique. [DCL23-C]
  39. Use parentheses for precedence of operation. [EXP00-C]
  40. Be aware of the short-circuit behavior of the logical AND and OR operators. [EXP02-C]
  41. Do not assume the size of a structure is the sum of the sizes of its members. [EXP03-C]
  42. Do not cast away a const qualification. [EXP05-C]
  43. Do not diminish the benefits of constants by assuming their values in expressions. [EXP07-C]
  44. Ensure pointer arithmetic is used correctly. [EXP08-C]
  45. Use sizeof to determine the size of a type or variable. [EXP09-C]
  46. Do not depend on the order of evaluation of subexpressions or the order in which side effects take place. [EXP10-C]
  47. Do not make assumptions regarding the layout of structures with bit-fields. [EXP11-C]
  48. Do not ignore values returned by functions. [EXP12-C]
  49. Treat relational and equality operators as if they were nonassociative. [EXP13-C]
  50. Beware of integer promotion when performing bitwise operations on integer types smaller than int. [EXP14-C]
  51. Do not place a semicolon on the same line as an if, for, or while statement. [EXP15-C]
  52. Do not compare function pointers to constant values. [EXP16-C]
  53. Do not perform bitwise operations in conditional expressions. [EXP17-C]
  54. Use braces for the body of an if, for, or while statement. [EXP19-C]
  55. Perform explicit tests to determine success, true and false, and equality. [EXP20-C]
  56. Understand the data model used by your implementation(s). [INT00-C.]
  57. Use rsize_t or size_t for all integer values representing the size of an object. [INT01-C.]
  58. Understand integer conversion rules. [INT02-C.]
  59. Enforce limits on integer values originating from tainted sources. [INT04-C.]
  60. Do not use input functions to convert character data if they cannot handle all possible inputs. [INT05-C.]
  61. Use strtol() or a related function to convert a string token to an integer. [INT06-C.]
  62. Use only explicitly signed or unsigned char type for numeric values. [INT07-C.]
  63. Verify that all integer values are in range. [INT08-C.]
  64. Ensure enumeration constants map to unique values. [INT09-C.]
  65. Do not assume a positive remainder when using the % operator. [INT10-C.]
  66. Do not make assumptions about the type of a plain int bit-field when used in an expression. [INT12-C.]
  67. Use bitwise operators only on unsigned operands. [INT13-C]
  68. Avoid performing bitwise and arithmetic operations on the same data. [INT14-C.]
  69. Use intmax_t or uintmax_t for formatted IO on programmer-defined integer types. [INT15-C.]
  70. Do not make assumptions about representation of signed integers. [INT16-C.]
  71. Define integer constants in an implementation-independent manner. [INT17-C.]
  72. Evaluate integer expressions in a larger size before comparing or assigning to that size. [INT18-C.]
  73. Understand the limitations of floating-point numbers. [FLP00-C]
  74. Take care in rearranging floating-point expressions [FLP01-C]
  75. Avoid using floating-point numbers when precise computation is needed [FLP02-C]
  76. Detect and handle floating-point errors [FLP03-C]
  77. Check floating-point inputs for exceptional values [FLP04-C]
  78. Don't use denormalized numbers [ FLP05-C]
  79. Convert integers to floating point for floating-point operations [FLP06-C]
  80. Cast the return value of a function that returns a floating-point type [FLP07-C]
  81. Understand how arrays work [ARR00-C]
  82. Do not apply the sizeof operator to a pointer when taking the size of an array [ARR01-C]
  83. Explicitly specify array bounds, even if implicitly defined by an initializer [ARR02-C]
  84. Represent characters using an appropriate type [STR00-C]
  85. Adopt and implement a consistent plan for managing strings [STR01-C]
  86. Sanitize data passed to complex subsystems [STR02-C]
  87. Do not inadvertently truncate a string [STR03-C]
  88. Use plain char for characters in the basic character set [STR04-C]
  89. Use pointers to const when referring to string literals [STR05-C]
  90. Do not assume that strtok() leaves the parse string unchanged [STR06-C]
  91. Use the bounds-checking interfaces for remediation of existing string manipulation code [STR07-C]
  92. Use managed strings for development of new string manipulation code [STR08-C]
  93. Don't assume numeric values for expressions with type plain character [STR09-C]
  94. Do not concatenate different type of string literals [STR10-C]
  95. Do not specify the bound of a character array initialized with a string literal [STR11-C]
  96. Adopt and implement a consistent and comprehensive error-handling policy [ERR00-C]
  97. Use ferror() rather than errno to check for FILE stream errors [ERR01-C]
  98. Avoid in-band error indicators [ERR02-C]
  99. Use runtime-constraint handlers when calling the bounds-checking interfaces [ERR03-C]
  100. Choose an appropriate termination strategy [ERR04-C]
  101. Application-independent code should provide error detection without dictating error handling [ERR05-C]
  102. Understand the termination behavior of assert() and abort() [ERR00-C]
  103. Prefer functions that support error checking over equivalent functions that don't [ERR07-C]
  104. Functions should validate their parameters [API00-C]
  105. Avoid laying out strings in memory directly before sensitive data [API01-C]
  106. Functions that read or write to or from an array should take an argument to specify the source or target size [API02-C]
  107. Create consistent interfaces and capabilities across related functions [API03-C]
  108. Provide a consistent and usable error-checking mechanism [API04-C]
  109. Use conformant array parameters [API05-C]
  110. Enforce type safety [API07-C]
  111. Avoid parameter names in a function prototype [API08-C]
  112. Compatible values should have the same type [API09-C]
  113. Avoid race conditions with multiple threads [CON00-C]
  114. Acquire and release synchronization primitives in the same module, at the same level of abstraction [CON01-C]
  115. Do not use volatile as a synchronization primitive [CON02-C]
  116. Ensure visibility when accessing shared variables [CON03-C]
  117. Join or detach threads even if their exit status is unimportant [CON04-C]
  118. Do not perform operations that can block while holding a lock [CON05-C]
  119. Ensure that every mutex outlives the data it protects [CON06-C]
  120. Ensure that compound operations on shared variables are atomic [CON07-C]
  121. Do not assume that a group of calls to independently atomic methods is atomic [CON08-C]
  122. Avoid the ABA problem when using lock-free algorithms [CON09-C]
  123. Compile cleanly at high warning levels [MSC00-C]
  124. Strive for logical completeness [MSC01-C]
  125. Use comments consistently and in a readable fashion [MSC04-C]
  126. Do not manipulate time_t typed values directly [MSC05-C]
  127. Beware of compiler optimizations [MSC06-C]
  128. Detect and remove dead code [MSC07-C]
  129. Character encoding: Use subset of ASCII for safety [MSC09-C]
  130. Character encoding: UTF8-related issues [MSC10-C]
  131. Incorporate diagnostic tests using assertions [MSC11-C]
  132. Detect and remove code that has no effect [MSC12-C]
  133. Detect and remove unused values [MSC13-C]
  134. Do not introduce unnecessary platform dependencies [MSC14-C]
  135. Do not depend on undefined behavior [MSC15-C]
  136. Finish every set of statements associated with a case label with a break statement [MSC17-C]
  137. Be careful while handling sensitive data, such as passwords, in program code [MSC18-C]
  138. For functions that return an array, prefer returning an empty array over a null value [MSC19-C]
  139. Do not use a switch statement to transfer control into a complex block [MSC20-C]
  140. Use robust loop termination conditions [MSC21-C]
  141. Use the setjmp(), longjmp() facility securely [MSC22-C]
  142. Beware of vendor-specific library and language differences [MSC23-C]
  143. Do not use deprecated or obsolescent functions [MSC24-C]
  144. Check for the existence of links when dealing with files [POS01-C]
  145. Follow the principle of least privilege [ POS02-C]
  146. Avoid using PTHREAD_MUTEX_NORMAL type mutex locks [POS04-C]
  147. Limit access to files by creating a jail [POS05-C]
  148. Be specific when dynamically loading libraries [WIN00-C]
  149. Do not forcibly terminate execution [WIN01-C]
  150. Restrict privileges when spawning child processes [WIN02-C]
  151. Understand HANDLE inheritance [WIN03-C]
  152. Consider encrypting function pointers [WIN04-C]