forked from PoliEcho-holding-org/kern
199 lines
6.2 KiB
Plaintext
199 lines
6.2 KiB
Plaintext
Coding Style
|
|
============
|
|
|
|
Indentation
|
|
-----------
|
|
All indents must be a tab character ('\t'). It is recommended to display tabs
|
|
as eight spaces to avoid extensive indentation. You shouldn't have more than
|
|
3 levels of indentation.
|
|
|
|
Braces
|
|
------
|
|
All braces should be placed on the same line as the statement they belong to.
|
|
```c
|
|
int main(void) {
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
The closing brace should be on it's own line, unless it's being followed by
|
|
a continuation of the statement (e.g. 'else' after an 'if').
|
|
```c
|
|
if (condition) {
|
|
doSomething();
|
|
} else {
|
|
doSomethingElse();
|
|
}
|
|
```
|
|
|
|
There may be a single statement without braces if it fits on a single line.
|
|
```c
|
|
// This is good
|
|
if (condition) doSomething();
|
|
|
|
// This is too long => bad
|
|
if (condition) doSomethingButLong(someParameter, someNumber * otherNumber, "A literal string");
|
|
```
|
|
|
|
Spaces
|
|
------
|
|
Spaces should be after most statements like 'while', 'for', 'if', etc.
|
|
Spaces should not be placed after 'sizeof' and 'alignof' statements.
|
|
There should not be spaces around the inside of a parenthesized expression, e.g.:
|
|
`int x = ( y * x ); // This is bad`
|
|
|
|
The '*' in pointer declarations, it is prefered to be appended to the
|
|
type name, e.g.:
|
|
```c
|
|
char* string; // Good
|
|
char** strings; // Good
|
|
int *intptr; // Bad
|
|
int *a, *b; // Allowed, but should be split into multiple declarations
|
|
```
|
|
|
|
Spaces should also be placed between binary and ternary operators, but
|
|
should not be placed after/before unary operators or member access operators.
|
|
|
|
Naming
|
|
------
|
|
_The hardest thing in programming_
|
|
Identifiers should use camelCase (starting with lowercase). In special
|
|
cases (e.g. syscall handlers) a short prefix separated with an underscore
|
|
may be used (e.g. 'sys_malloc').
|
|
|
|
Global variables (that should be sparse) and global functions need good,
|
|
descriptive names. A disk reading function shouldn't be called 'dskrd()'.
|
|
|
|
Local variables and functions don't need descriptive names, a loop counter
|
|
should be named 'i' and not loopCounter.
|
|
|
|
Some good naming examples:
|
|
```c
|
|
// Random good function names
|
|
int32_t findFreeBlock(uint32_t count);
|
|
int32_t ttyWrite(const void* buf, size_t len);
|
|
uint8_t getRtcRegister(uint8_t reg);
|
|
|
|
// Serial functions all start with 'serial'
|
|
int serialSetup();
|
|
void serialWrite(uint8_t byte);
|
|
uint8_t serialRead();
|
|
|
|
// Syscall handlers are prefixed with 'sys_'
|
|
int sys_malloc(struct intFrame iframe);
|
|
int sys_free(struct intFrame iframe);
|
|
```
|
|
|
|
Labels, for 'goto' statements or assembly, should be snake_case.
|
|
|
|
Typedefs vs Structs
|
|
-------------------
|
|
Typedefs should only be used if:
|
|
* It's a struct whose members shouldn't be accessed externally, e.g. FILE
|
|
* It clears confusion, e.g. 'i32' or 'int32_t' is better than just 'int'
|
|
There may be more, but it's better to not use them.
|
|
|
|
Functions
|
|
---------
|
|
Functions should be short and do one thing. If a function does multiple things,
|
|
see if you can split it up into multiple functions. Some indicators
|
|
of a good function are:
|
|
* It fits into 1-2 screenfulls (let those be 80x24)
|
|
* There shouldn't be more than ~10 local variables
|
|
|
|
In function prototypes, parameter names should be included. It can give more
|
|
insight into what it is supposed to be.
|
|
|
|
Goto
|
|
----
|
|
Using the 'goto' statement is fair in these cases:
|
|
* Exiting nested code
|
|
* Easier to read code
|
|
* Getting rid of redundant code
|
|
* Exiting from multiple points
|
|
|
|
Label names should be descriptive, should specify exactly what the goto
|
|
does (e.g. 'exit_free_buffer'). Avoid numbering these labels incase of having
|
|
to renumber the later.
|
|
|
|
Comments
|
|
--------
|
|
Write comments telling What code does, not How. Comments shouldn't be inside
|
|
a function body. There may be small comments on some trick or ugly thing in
|
|
a function, but avoid doing that too much. If you need to comment on how
|
|
everything in a function works, it's probably a really bad function.
|
|
|
|
Multiline comments should be over multiple lines. Don't write `/* Something */`.
|
|
They should look like this:
|
|
```c
|
|
/*
|
|
* This is a multiline comment
|
|
* The beggining and ending comment characters have their own lines.
|
|
* Each row also starts with an asterisk, making a nice column.
|
|
*/
|
|
```
|
|
|
|
Also it is recommended to comment on data in structs, since members may have
|
|
more abstract names.
|
|
|
|
Macros & Enums
|
|
--------------
|
|
_Yeah, we do a little magic_
|
|
|
|
Constant define macros must be UPPERCASE.
|
|
`#define FUNNY_NUM 0x69`
|
|
|
|
If there are multiple related constants, please use an enum.
|
|
CAPITALIZED macro names are appreciated, but function-like macros may have
|
|
lowercase names. Generally, inline functions are prefered over macros.
|
|
If a macro uses more than one statement, enclose them in their own scope.
|
|
```c
|
|
#define MAGIC(_x)\
|
|
if (_x > 0) doSomething(_x);
|
|
```
|
|
|
|
Things to look out for:
|
|
* Macros that affect controll flow. `#define FOO(_x) { if (_x < 0) return 1; }
|
|
* Macros that depend on local variables
|
|
* Macros used as l-values
|
|
* Forgetting about precedence. Just wrap everything in parenthesis
|
|
* Namespace collision, prefix everything in the macro with underscores
|
|
|
|
Other Stuff
|
|
----------
|
|
Here are some rules/recommendations that don't deserve their own category.
|
|
|
|
Inline Assembly
|
|
***************
|
|
If you don't need to, don't. But for architecture specific stuff, you may need
|
|
to. So just don't jump between functions and don't break anything. Also if you
|
|
think you can optimize better than the compiler, you're wrong.
|
|
|
|
Conditional Compilation
|
|
***********************
|
|
Try to avoid preprocessor conditionals inside .c source files. Instead write
|
|
conditionals inside the header and give a NOP version for the #else case.
|
|
These functions can be called uncoditionally. Empty inline functions work too.
|
|
|
|
Using Bool
|
|
**********
|
|
You may use bool, but are not required to. It does improve readability
|
|
|
|
Allocating Memory
|
|
*****************
|
|
The prefered way of allocating memory for a struct is:
|
|
`ptr = kmalloc(sizeof(*ptr));`
|
|
Casting the returned void pointer is redundant since C converts void pointers
|
|
to any other pointers.
|
|
|
|
Include Order
|
|
*************
|
|
The prefered way of ordering '#include' directives is as so:
|
|
* Include path includes (ones in <>)
|
|
* Local path includes (ones in "")
|
|
* Header implementation include, if you're implementing a header, include it last
|
|
|
|
Directives should be ordered by lenght, descending. If two or more includes
|
|
have the same length, order alphabetically.
|
|
|