`const` first, we do not require it.
But be consistent with the code around you! >c
void foo(const char *p, int i);
}
int foo(const int a, const bool b) {
}
int foo(int *const p) {
}
Integer Types ~
Of the built-in integer types only use `char`, `int`, `uint8_t`, `int8_t`,
`uint16_t`, `int16_t`, `uint32_t`, `int32_t`, `uint64_t`, `int64_t`,
`uintmax_t`, `intmax_t`, `size_t`, `ssize_t`, `uintptr_t`, `intptr_t`, and
`ptrdiff_t`.
Use `int` for error codes and local, trivial variables only.
Use care when converting integer types. Integer conversions and promotions can
cause non-intuitive behavior. Note that the signedness of `char` is
implementation defined.
Public facing types must have fixed width (`uint8_t`, etc.)
There are no convenient `printf` format placeholders for fixed width types.
Cast to `uintmax_t` or `intmax_t` if you have to format fixed width integers.
Type unsigned signed
`char` `%hhu` `%hhd`
`int` n/a `%d`
`(u)intmax_t` `%ju` `%jd`
`(s)size_t` `%zu` `%zd`
`ptrdiff_t` `%tu` `%td`
Booleans ~
Use `bool` to represent boolean values. >c
int loaded = 1; // ❌: loaded should have type bool.
Conditions ~
Don't use "yoda-conditions". Use at most one assignment per condition. >c
if (1 == x) {
if (x == 1) { //use this order
if ((x = f()) && (y = g())) {
Function declarations ~
Every function must not have a separate declaration.
Function declarations are created by the gen_declarations.lua script. >c
static void f(void);
static void f(void)
{
...
}
General translation unit layout ~
The definitions of public functions precede the definitions of static
functions. >c
<HEADER>
<PUBLIC FUNCTION DEFINITIONS>
<STATIC FUNCTION DEFINITIONS>
Integration with declarations generator ~
Every C file must contain #include of the generated header file, guarded by
#ifdef INCLUDE_GENERATED_DECLARATIONS.
Include must go after other #includes and typedefs in .c files and after
everything else in header files. It is allowed to omit #include in a .c file
if .c file does not contain any static functions.
Included file name consists of the .c file name without extension, preceded by
the directory name relative to src/nvim. Name of the file containing static
functions declarations ends with `.c.generated.h`, `*.h.generated.h` files
contain only non-static function declarations. >c
// src/nvim/foo.c file
#include <stddef.h>
typedef int FooType;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "foo.c.generated.h"
#endif
…
// src/nvim/foo.h file
#pragma once
…
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "foo.h.generated.h"
#endif
64-bit Portability ~
Code should be 64-bit and 32-bit friendly. Bear in mind problems of printing,
comparisons, and structure alignment.
- Remember that `sizeof(void *)` != `sizeof(int)`. Use `intptr_t` if you want
a pointer-sized integer.
- You may need to be careful with structure alignments, particularly for
structures being stored on disk. Any class/structure with a
`int64_t`/`uint64_t` member will by default end up being 8-byte aligned on a
64-bit system. If you have such structures being shared on disk between
32-bit and 64-bit code, you will need to ensure that they are packed the
same on both architectures. Most compilers offer a way to alter structure
alignment. For gcc, you can use `__attribute__((packed))`. MSVC offers
`#pragma pack()` and `__declspec(align())`.
- Use the `LL` or `ULL` suffixes as needed to create 64-bit constants. For
example: >c
int64_t my_value = 0x123456789LL;
uint64_t my_mask = 3ULL << 48;
sizeof ~
Prefer `sizeof(varname)` to `sizeof(type)`.
Use `sizeof(varname)` when you take the size of a particular variable.
`sizeof(varname)` will update appropriately if someone changes the variable
type either now or later. You may use `sizeof(type)` for code unrelated