COMP2017 C Style Guide
COMP2017 C Style Guide
Naming and variables
Naming convention for should follow snake case (snake_case). The variable name will contain an underscore where it will normally have a space.
Copyright By PowCoder代写 加微信 powcoder
Variable names in C should be short and to the point. However, global variables should incorporate heavier description to ensure they are correctly identi�ed and contain uniqueness. Be careful about mangling names that may be represented in other �les.
Only one variable per a line, do not use multi-variable declaration. Try to initialise variables to a default value (typically 0 or NULL, depending on the type), this avoids accidental usage of garbage data.
Acceptable:
char y = ‘y’;
int x = 10;
int* tmp_v = malloc(sizeof(int));
char y, x = ‘1’;
int someHiddenKey = 10;
Pointer types representation should be compact. The following shows two distinct styles that makes it easily identi�able as a pointer type.
int* i = NULL; or
int *i = NULL;
The above pointer type declarations are acceptable, the latter providing clarity when initialising with multiple variables on one line (although this is discouraged). The former is a little more succinct in its representation of the type.
File extensions
Use .h for header �les and .c for source �les.
Header �le guards
You should always eliminate multiple inclusion through the use of a header guard, typical convention is to use the header �le name in uppercase with _H su�x. Do acknowledge when header �les and header �le guard names can clash with any library or standard library header �le.
Lines should not exceed 80 characters
Even with wide screen monitors, default number of columns for terminals is 80 columns.
The wider the window the fewer windows we can have on a screen. More windows is better than wider windows.
We even view and print di� output correctly on all terminals and printers.
#ifndef MY_HEADER_FILE_H #define MY_HEADER_FILE_H
Constants and constants, enumerator values and variable constants should be clearly named in UPPER CASE (and snake case!).
Acceptable:
#define THIS_IS_A_CONSTANT 42
enum traffic { GREEN = 0,
YELLOW = 1,
RED = 2 };
#define x 30 enum traffic { green = 0,
yellow = 1,
red = 2 };
This helps distinguish between lower case variable names and globals/constants/enum types.
Indentation
Indentation is 4 characters long. (4 spaces, not \t). Your text editor should support soft tabs with the ability to specify the number of whitespace characters. However when working with on other projects, you should adapt to the style of the project.
Rationale: Although not as heretical as other decisions in this document, it appears to be a common standard to use 4 space indentation.
Braces and Spaces
Containing a space after a keyword is acceptable however it is desirable to not do this for sizeof,
alignof or attribute.
Keywords such as if, switch, case, for, do, while braces should have a space between the opening
brace and the last parenthesis. Acceptable:
if(condition) { }
Acceptable:
if (condition) { }
Acceptable:
v = sizeof(type)
v = sizeof( type )
Functions follow a space and a curly brace after the �nal parenthesis however a new line and curly brace after the �nal parenthesis is acceptable.
Acceptable:
void f(int j) { }
Acceptable:
void f(int j) {
are generally allowed if you feel that it helps with readability of your code, however a few recommendations when using typedef.
Never typedef:
Pointers (exception being, complex function pointers) Other typedefs
typedef other library structures or typedefs
Acceptable:
typedef struct { void* data;
int count; } container;
container c = { NULL, 0 };
typedef struct { void* data;
int count; } container;
typedef container lib_container;
container x = …
lib_container c = x; //Ack! What is this?
Why: This results in confusion between the original type and normal typedef, anyone reading your code may assume that lib_container and container are separate types.
typedef int* IntPtr
Why: This typedef is in�exible and does not improve readability, it’s in�exibility is outlined easily when we have a nested pointer ( IntPtr* ) e�ectively making the original typedef useless.
typedef uint32_t ui32_t
Why: This uint32_t is already a typedef, the name is already short enough to convey meaning of the type and creating a new typedef will result in confusion and unnecessary code.
Functions declarations should be made in the header �le or at the top of the �le (because C’s top- down parsing)
void my_function();
void my_function() { //Your code
Please do not arbitrarily scatter your function declarations and de�nitions through out your code. Keep it consistant and easy to manage. Declarations at the top or in a header �le and de�nitions below them.
Use of goto
Goto should not be used in your code and careless programmers can create problematic bugs with this method. There are instances where goto can be elegant when exiting and cleaning up functions, however, goto lends itself well to creating spaghetti code which goes against what C is trying to achieve.
Magic numbers, Macros and Enums
Magic Numbers
With the exception of very small programs and cleanly initialising your variables (set to 0, 1 or NULL), variables should not use magic numbers.
In the case where the problem requires a speci�c number, a macro should be in its place to make your life easier as a programmer and anyone else reading your code.
int x = 50; if (50 < x) {
Acceptable:
#define OFFSET (50) int x = 0;
if (OFFSET < x) {
Macros should be short, sweet and sanitary. Sanitising your macro is necessary to prevent logic errors in your code. Any variable that you use within a macro should be wrapped around parenthesis to ensure that any placement of multiple variables in its place are cleanly resolved.
Macro names should be in upper snakecase. Acceptable:
#define ADD(x,y) (x) + (y)
#define ADD(x,y) x + y
Multi-line Macros
It is good advice to avoid writing multi-line macros, however in the event that you will need to write such a macro it is advisable to write them in their own scope and variable names to start with the macro's name.
Acceptable:
#define PIN_SET()
TODO: Finish this section
Enumerator types can be used in place of constants when the constants are related or in e�ect, represent states or �ags.
The trade o� between enums and macros is in relation to size of the executable/memory.
Casting malloc, calloc, realloc
It is preferred when writing portable code to cast malloc, calloc or realloc. This is in desire for your C code to be compatible with C++.
Acceptable:
int* p = (int*) malloc(sizeof(int));
However, there is a valid argument against casting malloc, calloc or realloc. C implicitly promotes void* to the binding's type, therefore this is a redundant operation.
No dependent data in conditional expressions
To avoid some sneaky short circuiting bugs, please avoid the use of variable updates conditional expressions.
int s = 1;
//assume f sets p if(s || f(&p)) {
int x = *p; //Potential seg fault if short circuit occurs }
Not ideal:
int s = 1;
//assume f sets p if(f(&p) || s) {
int x = *p; //Works but is not good practice }
int s = 1;
//assume f sets p if(s) {
if(f(&p)) {
int x = *p; //Works but is not good practice
Thou shall not #ifdef, #if is all you need
When checking a macro existence or value, you can just use #if as an acceptable way of checking. This is �exible enough to detect the value or if the macro has been set.
End Comment
We are aiming for programmers to maintain consistency, if a section speci�es multiple acceptable styles it is implied that you maintain one style or the other, not both.
References
This style guide was in�uenced heavily from:
C Coding Standard - https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
Linux Kernel coding style - https://www.kernel.org/doc/html/v4.10/process/coding-style.html
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com