Home | History | Annotate | Download | only in doc
      1 # Fluoride Style Guide
      2 This document outlines the coding conventions and code style used in Fluoride.
      3 Its primary purpose is to provide explicit guidance on style so that developers
      4 are consistent with one another and spend less time debating style.
      5 
      6 ## Directory structure
      7 Directories at the top-level should consist of major subsystems in Fluoride.
      8 Each subsystem's purpose should be documented in the `doc/directory_layout.md`
      9 file, even if it seems obvious from the name.
     10 
     11 For a subsystem that contains code, its directory structure should look like:
     12 ```
     13   Android.mk
     14   include/
     15   src/
     16   test/
     17 ```
     18 Further, the directory structure inside `src/` and `include/` should be
     19 mirrored. In other words, if `src/` contains a subdirectory called `foo/`,
     20 `include/` must also have a subdirectory named `foo/`.
     21 
     22 ## Target architecture
     23 Fluoride targets a variety of hardware and cannot make many assumptions about
     24 memory layout, sizes, byte order, etc. As a result, some operations are
     25 considered unsafe and this section outlines the most important ones to watch out
     26 for.
     27 
     28 ### Pointer / integer casts
     29 In general, do not cast pointers to integers or vice versa.
     30 
     31 The one exception is if an integer needs to be temporarily converted to a
     32 pointer and then back to the original integer. This style of code is typically
     33 needed when providing an integral value as the context to a callback, as in the
     34 following example.
     35 ```
     36 void my_callback(void *context) {
     37   uintptr_t arg = context;
     38 }
     39 
     40 set_up_callback(my_callback, (uintptr_t)5);
     41 ```
     42 Note, however, that the integral value was written into the pointer and read
     43 from the pointer as a `uintptr_t` to avoid a loss of precision (or to make the
     44 loss explicit).
     45 
     46 ### Byte order
     47 It is not safe to assume any particular byte order. When serializing or
     48 deserializing data, it is unsafe to memcpy unless both source and destination
     49 pointers have the same type.
     50 
     51 ## Language
     52 Fluoride is written in C99 and should take advantage of the features offered by
     53 it. However, not all language features lend themselves well to the type of
     54 development required by Fluoride. This section provides guidance on some of the
     55 features to embrace or avoid.
     56 
     57 ### C Preprocessor
     58 The use of the C preprocessor should be minimized. In particular:
     59 * use functions or, if absolutely necessary, inline functions instead of macros
     60 * use `static const` variables instead of `#define`
     61 * use `enum` for enumerations, not a collection of `#define`s
     62 * minimize the use of feature / conditional macros
     63 
     64 The last point is perhaps the most contentious. It's well-understood that
     65 feature macros are useful in reducing code size but it leads to an exponential
     66 explosion in build configurations. Setting up, testing, and verifying each of
     67 the `2^n` build configurations is untenable for `n` greater than, say, 4.
     68 
     69 ### C++
     70 Although C++ offers constructs that may make Fluoride development faster,
     71 safer, more pleasant, etc. the decision _for the time being_ is to stick with
     72 pure C99. The exceptions are when linking against libraries that are written
     73 in C++. At the time of writing these libraries are `gtest` and `tinyxml2`,
     74 where the latter is a dependency that should be eliminated in favor of simpler,
     75 non-XML formats.
     76 
     77 ### Variadic functions
     78 Variadic functions are dangerous and should be avoided for most code. The
     79 exception is when implementing logging since the benefits of readability
     80 outweigh the cost of safety.
     81 
     82 ### Functions with zero arguments
     83 Functions that do not take any arguments (0 arity) should be declared like so:
     84 ```
     85 void function(void);
     86 ```
     87 Note that the function explicitly includes `void` in its parameter list to
     88 indicate to the compiler that it takes no arguments.
     89 
     90 ### Variable declarations
     91 Variables should be declared one per line as close to initialization as possible.
     92 In nearly all cases, variables should be declared and initialized on the same line.
     93 Variable declarations should not include extra whitespace to line up fields. For
     94 example, the following style is preferred:
     95 ```
     96   int my_long_variable_name = 0;
     97   int x = 5;
     98 ```
     99 whereas this code is not acceptable:
    100 ```
    101   int my_long_variable_name = 0;
    102   int                     x = 5;
    103 ```
    104 
    105 As a result of the above rule to declare and initialize variables together,
    106 `for` loops should declare and initialize their iterator variable in the
    107 initializer statement:
    108 ```
    109   for (int i = 0; i < 10; ++i) {
    110     // use i
    111   }
    112 ```
    113 
    114 ### Contiguous memory structs
    115 Use C99 flexible arrays as the last member of a struct if the array needs
    116 to be allocated in contiguous memory with its containing struct.
    117 A flexible array member is writen as `array_name[]` without a specified size.
    118 For example:
    119 ```
    120 typedef struct {
    121   size_t length;
    122   uint8_t data[];
    123 } buffer_t;
    124 
    125 // Allocate a buffer with 128 bytes available for my_buffer->data.
    126 buffer_t *my_buffer = malloc(sizeof(buffer_t) + 128);
    127 uint8_t *data = my_buffer->data;
    128 ```
    129 
    130 ### Pointer arithmetic
    131 Avoid pointer arithmetic when possible as it results in difficult to read code.
    132 Prefer array-indexing syntax over pointer arithmetic.
    133 
    134 In particular, do not write code like this:
    135 ```
    136 typedef struct {
    137   size_t length;
    138 } buffer_t;
    139 
    140 buffer_t *my_buffer = malloc(sizeof(buffer_t) + 128);
    141 uint8_t *data = (uint8_t *)(my_buffer + 1);
    142 ```
    143 Instead, use zero-length arrays as described above to avoid pointer arithmetic
    144 and array indexing entirely.
    145 
    146 ### Boolean type
    147 Use the C99 `bool` type with values `true` and `false` defined in `stdbool.h`.
    148 Not only is this a standardized type, it is also safer and provides more
    149 compile-time checks.
    150 
    151 ### Booleans instead of bitfields
    152 Use booleans to represent boolean state, instead of a set of masks into an
    153 integer. It's more transparent and readable, and less error prone.
    154 
    155 ### Function names as strings
    156 C99 defines `__func__` as an identifier that represents the function's name
    157 in which it is used. The magic identifier `__FUNCTION__` should not be used
    158 as it is a non-standard language extension and an equivalent standardized
    159 mechanism exists. In other words, use `__func__` over `__FUNCTION__`.
    160 
    161 ## Fluoride conventions
    162 This section describes coding conventions that are specific to Fluoride.
    163 Whereas the _Language_ section describes the use of language features, this
    164 section describes idioms, best practices, and conventions that are independent
    165 of language features.
    166 
    167 ### Memory management
    168 Use `osi_malloc` or `osi_calloc` to allocate bytes instead of plain `malloc`.
    169 Likewise, use `osi_free` over `free`. These wrapped functions provide additional
    170 lightweight memory bounds checks that can help track down memory errors.
    171 
    172 By convention, functions that contain `*_new` in their name are allocation
    173 routines and objects returned from those functions must be freed with the
    174 corresponding `*_free` function. For example, list objects returned from
    175 `list_new` should be freed with `list_free` and no other freeing routine.
    176 
    177 ### Asserts
    178 Use `assert` liberally throughout the code to enforce invariants. Assertions
    179 should not have any side-effects and should be used to detect programming logic
    180 errors.
    181 
    182 At minimum, every function should assert expectations on its arguments. The
    183 following example demonstrates the kinds of assertions one should make on
    184 function arguments.
    185 ```
    186   size_t open_and_read_file(const char *filename, void *target_buffer, size_t max_bytes) {
    187     assert(filename != NULL);
    188     assert(filename[0] != '\0');
    189     assert(target_buffer != NULL);
    190     assert(max_bytes > 0);
    191 
    192     // function implementation begins here
    193   }
    194 ```
    195 
    196 ## Header files
    197 In general, every source file (`.c` or `.cpp`) in a `src/` directory should
    198 have a corresponding header (`.h`) in the `include/` directory.
    199 
    200 ### Template header file
    201 ```
    202 [copyright header]
    203 
    204 #pragma once
    205 
    206 #include <system/a.h>
    207 #include <system/b.h>
    208 
    209 #include "subsystem/include/a.h"
    210 #include "subsystem/include/b.h"
    211 
    212 typedef struct alarm_t alarm_t;
    213 typedef struct list_t list_t;
    214 
    215 // This comment describes the following function. It is not a structured
    216 // comment, it's English prose. Function arguments can be referred to as
    217 // |param|. This function returns true if a new object was created, false
    218 // otherwise.
    219 bool template_new(const list_t *param);
    220 
    221 // Each public function must have a comment describing its semantics. In
    222 // particular, edge cases, and whether a pointer argument may or may not be
    223 // NULL.
    224 void template_use_alarm(alarm_t *alarm);
    225 ```
    226 
    227 ### License header
    228 Each header file must begin with the following Apache 2.0 License with `<year>`
    229 and `<owner>` replaced with the year in which the file was authored and the
    230 owner of the copyright, respectively.
    231 ```
    232 /******************************************************************************
    233  *
    234  *  Copyright (C) <year> <owner>
    235  *
    236  *  Licensed under the Apache License, Version 2.0 (the "License");
    237  *  you may not use this file except in compliance with the License.
    238  *  You may obtain a copy of the License at:
    239  *
    240  *  http://www.apache.org/licenses/LICENSE-2.0
    241  *
    242  *  Unless required by applicable law or agreed to in writing, software
    243  *  distributed under the License is distributed on an "AS IS" BASIS,
    244  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    245  *  See the License for the specific language governing permissions and
    246  *  limitations under the License.
    247  *
    248  ******************************************************************************/
    249 ```
    250 
    251 ### Include guard
    252 After the license header, each header file must contain the include guard:
    253 ```
    254 #pragma once
    255 ```
    256 This form is used over traditional `#define`-based include guards as it is less
    257 error-prone, doesn't pollute the global namespace, is more compact, and can
    258 result in faster compilation.
    259 
    260 ## Formatting
    261 Code formatting is pretty arbitrary, but the codebase is easier to follow if
    262 everyone uses the same style. Individuals may not agree with every aspect of
    263 the formatting rules, and some of the rules may take some getting used to,
    264 but it is important that all engineers follow the formatting rules so we can all
    265 understand and read the code easily.
    266 
    267 ### White space
    268 * use only spaces, indent 2 spaces at a time
    269 * no trailing whitespaces at the end of a line
    270 * no tab characters
    271 * use one blank line to separate logical code blocks, function definitions,
    272   and sections of a file
    273 
    274 ```
    275 // Space after keyword in conditionals and loops.
    276 // No space immeidately before or after parentheses.
    277 if (foo)
    278 
    279 // Space surrounding binary operators.
    280 if (foo < 5)
    281 
    282 // Space after comma.
    283 for (int x = 0, y = 0; x; ++y)
    284 
    285 // No space between unary operators and their argument.
    286 ++x;
    287 z = -y;
    288 
    289 // No space between function name and open parenthesis.
    290 call_my_fn(arg1, arg2);
    291 
    292 // Space before * in variable declaration.
    293 int *x = NULL;
    294 
    295 // Space after // beginning a comment.
    296 // Notice the space between "//" and "N".
    297 ```
    298 
    299 Use only spaces, and indent 2 spaces at a time. Do not use tab characters in the
    300 codebase.
    301 
    302 Use a single blank line to separate logical code blocks, function definitions,
    303 and sections of a file.
    304 
    305 ### Brace style
    306 ```
    307 // Open curly braces are never on a line by themselves.
    308 void my_function(void) {
    309   // Conditional statements with only one child statement should elide braces.
    310   // The child statement must be on a new line, indented by 2 spaces.
    311   if (foo)
    312     do_bar();
    313   else
    314     do_baz();
    315 
    316   // Conditionals with a branch containing more than one child statement forces
    317   // braces on both branches.
    318   if (foo) {
    319     do_bar();
    320   } else {
    321     do_baz();
    322     ++var1;
    323   }
    324 }
    325 ```
    326