forked from Justasic/Kernel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCodingStyle.txt
More file actions
467 lines (327 loc) · 13.9 KB
/
CodingStyle.txt
File metadata and controls
467 lines (327 loc) · 13.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
Coding Standard
1. Purpose
This document is designed to define the coding standard used inside this kernel.
It will tell you how to name files, functions, variables, etc. as well as define
what may be used and where.
2. C coding style - brackets
All curley brackets in C MUST be on their own lines. This includes
if-statements, function-statements, else-statements, etc.
Functions must be defined like the following:
typename_t function(arguments...)
{
...
operations
...
}
Don't put multiple statements on a single line unless you have
something to hide:
if (condition) do_this;
do_something_everytime;
Do not unnecessarily use braces where a single statement will do.
if (condition)
action();
and
if (condition)
do_this();
else
do_that();
Multi-line if-statements which require brackets shall follow the same bracket standard
as function declarations:
if (condition)
{
...
operations
...
}
else if (another condition)
{
...
operations
...
}
else
{
...
operations
...
}
Note that the two may be mixed, so the following is allowed to happen:
if (condition)
{
...
operations
...
}
else if (another condition)
operation...
else
{
...
operations
...
}
This includes all keywords and functions in the C language except
a few corner cases (such as do-while):
do
{
} while (operation);
Initialzer lists are defined a as follows:
unsigned char variable[] = {
...,
things,
...,
};
These are examples of what NOT to do:
if (condition) {
operation;
} else {
...
operations
...
}
do {
blah;
argh;
}
while(true);
while (derp) {
things;
}
3. C coding style - Spacing
Spacing is defined quite differently in this project than many others.
Spacing is strictly followed because many blocks of code can become
cumbersome to read if they're not spaced apart properly.
Tabs are defined as 8 spaces. If the code is too large to fit on the
screen then the code has become too complex and should be refactored.
All code should fit in 127 character rows.
Get a decent editor and don't leave whitespace at the end of lines.
Function declarations should NOT have a space between the parentheses
and the function name. Example:
void MyFunction(char argument1, int argument2)
Example of what NOT to do:
void MyFunction (char argument1, int argument2)
Use a space after these keywords:
if, switch, case, for, do, while
but not with sizeof, typeof, alignof, or __attribute__. E.g.,
s = sizeof(struct file);
Do not add spaces around (inside) parenthesized expressions. This example is
*bad*:
s = sizeof( struct file );
When declaring pointer data or a function that returns a pointer type, the
preferred use of '*' is adjacent to the data name or function name and not
adjacent to the type name. Examples:
char *linux_banner;
unsigned long long memparse(char *ptr, char **retptr);
char *match_strdup(substring_t *s);
Use one space around (on each side of) most binary and ternary operators,
such as any of these:
= + - < > * / % | & ^ <= >= == != ? : + -
but no space after unary operators:
& * ~ ! sizeof typeof alignof __attribute__ defined
no space before the postfix increment & decrement unary operators:
++ --
no space after the prefix increment & decrement unary operators:
++ --
and no space around the '.' and "->" structure member operators.
Optionally, if a multiple assignment operation is happening in a single block, do try
and align the assignment operators, an exception to this is if the line is too long.
Example (taken from above):
hole_header->magic = HEAP_MAGIC;
hole_header->is_hole = true;
hole_header->size = orig_hole_size - new_size;
instead of:
hole_header->magic = HEAP_MAGIC;
hole_header->is_hole = true;
hole_header->size = orig_hole_size - new_size;
When large blocks of code have multiple declarations and function calls, try and space
things out a bit so it does not appear as though there's a big chunk of text. Almost
all if-statements, while-statements, etc. will have a space before and after the statement.
This breaks the statement away from any initialized variables or function calls used in the
function. The (usual) only exception to this is when a variable is initialized for the
statement. An example:
void FreeFrame(page_t *page)
{
uint32_t frame;
if (!(frame = page->frame))
return; // The given page didn't actually have an allocated frame!
ClearFrame(frame); // Frame is now free again.
page->frame = 0x0; // Page now doesn't have a frame.
}
May be typed as above and be accepted, but it really should look like this:
void FreeFrame(page_t *page)
{
uint32_t frame;
if (!(frame = page->frame))
return; // The given page didn't actually have an allocated frame!
ClearFrame(frame); // Frame is now free again.
page->frame = 0x0; // Page now doesn't have a frame.
}
Here you can see that the if statement is 'floating' from the rest of the code in the function scope.
This is much easier to read and understand the function quickly without having to decouple the code
from the variable declarations and function calls. Another example:
if (orig_hole_size - new_size > 0)
{
header_t *hole_header = (header_t *)(orig_hole_pos + sizeof(header_t) + size + sizeof(footer_t));
hole_header->magic = HEAP_MAGIC;
hole_header->is_hole = true;
hole_header->size = orig_hole_size - new_size;
footer_t *hole_footer = (footer_t *)((uint32_t)hole_header + orig_hole_size - new_size - sizeof(footer_t));
if ((uint32_t)hole_footer < heap->end_address)
{
hole_footer->magic = HEAP_MAGIC;
hole_footer->header = hole_header;
}
// Put the new hole in the index;
InsertOrderedArray((void*)hole_header, &heap->index);
}
This is difficult to see what is what, lets break it up a bit:
if (orig_hole_size - new_size > 0)
{
header_t *hole_header = (header_t *)(orig_hole_pos + sizeof(header_t) + size + sizeof(footer_t));
hole_header->magic = HEAP_MAGIC;
hole_header->is_hole = true;
hole_header->size = orig_hole_size - new_size;
footer_t *hole_footer = (footer_t *)((uint32_t)hole_header + orig_hole_size - new_size - sizeof(footer_t));
if ((uint32_t)hole_footer < heap->end_address)
{
hole_footer->magic = HEAP_MAGIC;
hole_footer->header = hole_header;
}
// Put the new hole in the index;
InsertOrderedArray((void*)hole_header, &heap->index);
}
Here we see that the hole_footer variable is defined just above the if-statement because it's used
exclusively inside the if-statement and could possibly be used outside the statement. This is also
to separate it from the hole_header structure which is being filled out and could be easily misinterpreted
as part of that filling-out process instead of being a separate variable.
4. C coding style - Function and Variable Naming
All function names shall be in Pascal case. See: http://c2.com/cgi/wiki?PascalCase
Pascal case is defined as the first letter of a word in the function name shall be
uppercase, and the remaining letters shall be lower case. Any single-letter word shall
be upper case (such as 'A' as in "I have A"). Any acronyms shall also be all uppercase.
An example:
void InitializePIT(void);
void VGAWriteNString(char *str, size_t sz);
No function shall EVER use Camal case, your code WILL BE REJECTED if it uses Camal case.
It is ugly and I hate it. No function shall EVER have underscores in it unless it is an
internal function used in a single source file.
Function names should be clear and understandable, acronyms must be common enough to be
understood by others (don't invent new acronyms basically). An example of a non-clear
function name:
void VGAWNString(void);
Although it may be nice because it's short (eg, the 'W' would stand for 'Write'), it is
unclear what the function may do. Functions must be defined with full words (an exception
may be "init" instead of "initialize") and common acronyms (eg, PIT stands for Programmable
Interrupt Timer).
ALL CODE (excluding comments) MUST USE AMERICAN ENGLISH!
ANY CODE WHICH DOES NOT FOLLOW THIS WILL BE REJECTED REGARDLESS!
variable names may be named in whatever way you wish to name them, just be sure to explain
them well unless they are self-explanatory.
structures and typedefs may be used but structures which are typedef'ed must end in the
suffix '_s' and their typedef must end in '_t'. This allows for easy searching of what
that type is using a tool such as grep.
5. C coding style - Macros
Any multi-level macro shall have a space between the macro's '#' and the macro operation,
space levels depend on how deep into the macro scope said macro is. An example:
#ifndef HAVE_SOME_FUNC
# ifdef __CLANG__
# define SomeFunc ClangSomeFunc
# else
# define SomeFunc GCCSomeFunc
# endif // __CLANG__
#endif // HAVE_SOME_FUNC
This makes it MUCH easier to read macro scopes and know where a scope ends and begins.
Having all the '#' characters at the beginning also makes it a bit difficult to read
(as humans, we read words, not symbols).
Names of macros defining constants and labels in enums are capitalized.
#define CONSTANT 0x12345
Enums are preferred when defining several related constants.
CAPITALIZED macro names are appreciated but macros resembling functions
may be named in lower case.
Generally, inline functions are preferable to macros resembling functions.
Macros with multiple statements should be enclosed in a do - while block:
#define macrofun(a, b, c) \
do { \
if (a == 5) \
do_this(b, c); \
} while (0)
Things to avoid when using macros:
1) macros that affect control flow:
#define FOO(x) \
do { \
if (blah(x) < 0) \
return -EBUGGERED; \
} while(0)
is a _very_ bad idea. It looks like a function call but exits the "calling"
function; don't break the internal parsers of those who will read the code.
2) macros that depend on having a local variable with a magic name:
#define FOO(val) bar(index, val)
might look like a good thing, but it's confusing as hell when one reads the
code and it's prone to breakage from seemingly innocent changes.
3) macros with arguments that are used as l-values: FOO(x) = y; will
bite you if somebody e.g. turns FOO into an inline function.
4) forgetting about precedence: macros defining constants using expressions
must enclose the expression in parentheses. Beware of similar issues with
macros using parameters.
#define CONSTANT 0x4000
#define CONSTEXP (CONSTANT | 3)
6. C coding style - Inline assembly
In architecture-specific code, you may need to use inline assembly to interface
with CPU or platform functionality. Don't hesitate to do so when necessary.
However, don't use inline assembly gratuitously when C can do the job. You can
and should poke hardware from C when possible.
Consider writing simple helper functions that wrap common bits of inline
assembly, rather than repeatedly writing them with slight variations. Remember
that inline assembly can use C parameters.
Large, non-trivial assembly functions should go in .S files, with corresponding
C prototypes defined in C header files. The C prototypes for assembly
functions should use "asmlinkage".
You may need to mark your asm statement as volatile, to prevent GCC from
removing it if GCC doesn't notice any side effects. You don't always need to
do so, though, and doing so unnecessarily can limit optimization.
When writing a single inline assembly statement containing multiple
instructions, put each instruction on a separate line in a separate quoted
string, and end each string except the last with \n\t to properly indent the
next instruction in the assembly output:
__asm__ ("magic %reg1, #42\n\t"
"more_magic %reg2, %reg3"
: /* outputs */ : /* inputs */ : /* clobbers */);
7. C coding style - Editor modelines and other cruft
Some editors can interpret configuration information embedded in source files,
indicated with special markers. For example, emacs interprets lines marked
like this:
-*- mode: c -*-
Or like this:
/*
Local Variables:
compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
End:
*/
Vim interprets markers that look like this:
/* vim:set sw=8 noet */
Do not include any of these in source files. People have their own personal
editor configurations, and your source files should not override them. This
includes markers for indentation and mode configuration. People may use their
own custom mode, or may have some other magic method for making indentation
work correctly.
8. C coding style - The inline disease
There appears to be a common misperception that gcc has a magic "make me
faster" speedup option called "inline". While the use of inlines can be
appropriate (for example as a means of replacing macros), it
very often is not. Abundant use of the inline keyword leads to a much bigger
kernel, which in turn slows the system as a whole down, due to a bigger
icache footprint for the CPU and simply because there is less memory
available for the pagecache. Just think about it; a pagecache miss causes a
disk seek, which easily takes 5 milliseconds. There are a LOT of cpu cycles
that can go into these 5 milliseconds.
A reasonable rule of thumb is to not put inline at functions that have more
than 3 lines of code in them. An exception to this rule are the cases where
a parameter is known to be a compiletime constant, and as a result of this
constantness you *know* the compiler will be able to optimize most of your
function away at compile time.
Often people argue that adding inline to functions that are static and used
only once is always a win since there is no space tradeoff. While this is
technically correct, gcc is capable of inlining these automatically without
help, and the maintenance issue of removing the inline when a second user
appears outweighs the potential value of the hint that tells gcc to do
something it would have done anyway.