Consistent
and Minimal
Most important rules:
Be consistent.
Be minimal.
Read these sections carefully.
Text file layout
Tab size is 8 spaces.
Shift width (indentation) is 4 spaces.
Column width 79 char, so it fits well with 80 col terminal.
Indentation is always one shift-width(4):
printf("closing file %s on server
",
file_name);
printf("closing file %s on server
",
file_name);
Braces
open and close braces of a section should be on the same level.
if (close_files) {
fclose(fp1);
fclose(fp2);
}
if (close_files)
{
fclose(fp1);
fclose(fp2);
}
Breaking a long line
when breaking up a long line, it should continue with one shift-width for
indentation
if (line_length>1 && (screen->sz->verticalsz->vertical
|| explicit_lines))
{
printf("this is a test section that will show how to handle "
"long lines, such as %s which is %d lines long",
"this", 2);
SetWindowText( hWnd,
"Button Name" );
}
if (line_length>1 && (screen->sz->verticalsz->vertical
|| explicit_lines))
{
printf("this is a test section that will show how to handle "
"long lines, such as %s which is %d lines long", "this", 2);
SetWindowText(hWnd, "Button Name");
}
if
for
while
statement
if/for/while statement that takes more than one line should always have
braces; same thing goes when the then/loop part is more than one line
for (ret=0; ret
if (slot.dwBus==pciScan.cardSlot[ret].dwBus &&
slot.dwSlot==pciScan.cardSlot[ret].dwSlot &&
slot.dwFunction==pciScan.cardSlot[ret].dwFunction)
{
break;
}
if (x==y)
{
my_func(param1, param2, param3, param4, param5, param6,
param7);
}
Functions
prototypes space
function prototypes should be spaced like function calls
void do_keyboard_input( int key,
char *name,
int list_box,
BOOL is_read,
BOOL is_password )
{
// functions code
}
void do_keyboard_input(int key, char *name, int list_box, BOOL
is_read, BOOL is_password);
// in header file
void do_keyboard_input(int key, char *name, int list_box,
BOOL is_read, BOOL is_password);
// in code file
void do_keyboard_input(int key, char *name, int list_box,
BOOL is_read, BOOL is_password)
{
// functions code
}
// if you need to comment parameters
void do_keyboard_input(
int key, // Encryption key
char *name, // encrypted user name
int list_box, // list of destinations to choose from
BOOL is_read,
BOOL is_password) // destination specific psw
{
// functions code
}
Unneeded casting
do not cast void *, this is
unneeded in C.
estream = (estream_t *)malloc(sizeof(*estream));
estream = malloc(sizeof(*estream));
Do not cast
function prototypes
do not cast function prototypes - if the implementation changes in the
future, it will be hard to discover. the only exception is typecasting
xxx_free() functions (functions from type void xxx_close(xxx_t *xxx)).
typedef void (*etimer_func_t)(void *);
void event_timer_set(double ms, etimer_func_t func, void *data);
void estream_read(estream_t *estream)
{
read(estream->fd);
}
void do_something(void)
{
estream_t *estream;
event_timer_set(0, (etimer_func_t) estream_read, estream);
}
void estream_read(estream_t *estream)
{
read(estream->fd);
}
void estream_read_et(void *o)
{
estream_read((estream_t *)o);
}
void do_something(void)
{
estream_t *estream;
event_timer_set(0, estream_read_et, estream);
}
void estream_read(void *o)
{
estream_t *estream = o;
read(estream->fd);
}
void do_something(void)
{
estream_t *estream;
event_timer_set(0, estream_read, estream);
}
switch
statement
switch statements should have the case on the same level, no space before ':'.
if the case is one line, then one space after ':'.
never 'break' in 'default'.
switch (selection)
{
case KEY_UP :
x--;
break;
case KEY_DOWN :
x++;
break;
}
switch (selection)
{
case KEY_UP:
x--;
break;
case KEY_DOWN:
x++;
break;
}
switch (selection)
{
case KEY_UP: x--; break;
case KEY_DOWN: x++; break;
}
switch (selection)
{
case KEY_UP: x--; break;
case KEY_DOWN: x++; break;
default: invalid = 1; break;
}
switch (selection)
{
case KEY_UP: x--; break;
case KEY_DOWN: x++; break;
default: invalid = 1;
}
switch (selection)
{
case KEY_UP: key = UP; break;
case KEY_DOWN: key = DN; break;
case KEY_LEFT: key = LEFT; break;
case KEY_RIGHT: key = RIGHT; break;
default: key = NONE;
}
Spaces
no space between function name and opening parenthesis
no space between opening parenthesis and first parameter
one space after comma:
printf ("hello %s
", "world");
printf( "hello world
" );
printf("hello world
","world");
printf("hello %s
", "world");
one space after reserved words before the opening parenthesis:
if(close_file)
if (close_file)
'then' part of if
statement
'then' part of if statement should be in a separete line:
reason: allows to debug the if and see when it is run.
if (close_file) fclose(fp);
if (close_file)
fclose(fp);
else if
else if
statements should be on the same level at the starting
if reason: this is similar to switch statement
if (!strcmp(argv[1],"--help")) print_usage();
else if (!strcmp(argv[1], "--run")) {
run_application();
print_results();
} else print_error();
if (!strcmp(argv[1], "--help"))
print_usage();
else if (!strcmp(argv[1], "--run"))
{
run_application();
print_results();
}
else
print_error();
return
return statements should not have parentheses and should not have a space
after them:
return (0);
return 0;
return ;
return;
do not use unneeded
parentheses in expressions
if ((a!=b) || (c!=d))
...
if (a!=b || c!=d)
...
do not call return at the end of
a function returning void
void f(void)
{
printf("hello");
return;
}
void f(void)
{
printf("hello");
}
should not separate with more than one
blank line between sections, functions etc.
structure and enum
definitions
structure and enum definitions, itializations should open { at the same line.
it is recommended that the name will end with a _t. typedef the struct,
to make it easy to use later on.
typedef struct _WD_INTERNAL {
int setup;
int offset;
} WD_INTERNAL;
typedef struct
{
int setup;
int offset;
} wd_internal_t;
struct wd_internal_t {
int setup;
int offset;
};
// when forward structure definition needed:
typedef struct wd_internal_t {
struct wd_internal_t *next;
int setup;
int offset;
} wd_internal_t;
typedef struct {
int setup;
int offset;
} wd_internal_t;
wd_internal_t wd_initial = {
8,
16,
};
/* close all files */
fclose(fp);
// close all files
fclose(fp);
comments should be aligned as the code they comment, or one space after
the end of the line.
/*
* close all files
*/
fclose(fp);
//
// close all files
//
fclose(fp);
/* close all files */
fclose(fp);
GOOD better:
// close all files
fclose(fp);
fclose(fp); // close all files
comments which occupy more than one line should adhere to the following
guidline
//
// close all the files that were opened before the function was called
// and send them to the output file
//
fclose(fp);
// close all the files that were opened before the function was called
// and send them to the output file
fclose(fp);
Comment should never be ident more the 4 spaces even in structures.
If longer, put the comment at the line above.
typedef struct {
isa_pnp_id search_id; /* if search_id.vendor[0]==0 - scan all vendor
* IDs
* if searchId.dwSerial==0 - scan all serial
* numbers */
int cards; /* number of cards found */
isa_pnp_card card[ISAPNP_CARDS]; /* cards found */
} wd_isapnp_scan_cards_t;
typedef struct {
isa_pnp_id search_id; /* if search_id.vendor[0]==0 - scan
* all vendor IDs
* if searchId.dwSerial==0 - scan all
* serial numbers */
int cards; /* number of cards found */
isa_pnp_card card[ISAPNP_CARDS]; /* cards found */
} wd_isapnp_scan_cards_t;
typedef struct {
/* if search_id.vendor[0]==0 - scan all vendor IDs
* if searchId.dwSerial==0 - scan all serial numbers */
isa_pnp_id search_id;
int cards; /* number of cards found */
isa_pnp_card card[ISAPNP_CARDS]; /* cards found */
} wd_isapnp_scan_cards_t;
typedef struct {
// if search_id.vendor[0]==0 - scan all vendor IDs
// if searchId.dwSerial==0 - scan all serial numbers
isa_pnp_id search_id;
int cards; // number of cards found
isa_pnp_card card[ISAPNP_CARDS]; // cards found
} wd_isapnp_scan_cards_t;
Comments of XXX should be <keywords>: <comment>. multiple names
should be separated with a '/':
XXX: derry: move to compat
XXX derry: ANDROID move to compat
XXX derry: arik: move to compat
XXX: move to compat
XXX derry: move to compat
XXX derry ANDROID: move to compat
XXX derry/arik: move to compat
for
or
while
loop
common sense should come into play when deciding whether to use
for
or while
loops
i = 0;
while (i<10)
{
...
i++;
}
for (i = 0; i<10; i++)
...;
for (p = p->next; p; p = p->next)
...;
while (p = p->next)
...;
while for if
without a statement
while(pop_first(list))
;
while(pop_first(list));
for(i=0; i<*p; i++)
;
for (i=0; i<*p; i++);
if (a>b+10)
;
else if (a>b+5)
do_x();
else if (a>b+2)
;
else
do_y();
if (a>b+10);
else if (a>b+5)
do_x();
else if (a>b+2);
else
do_y();
Spacing
One space after
assignment
put one space before and after an assignment.
int a=0;
x= x+1;
bits|=BIT5;
int a = 0;
x = x+1;
bits |= BIT5;
Assignment in
for loop
if it is in a for
loop, you can skip the spaces. if you skip
one of the spaces, skip both
for (i= 0; i; i--)
printf("%d", i);
for (i=0; i; i--)
printf("%d", i);
for (i = 0; i; i--)
printf("%d", i);
No space
before statement seperator
don't put a space before a statement seperator, put one after it
for (i=0 ;i ;i--, j*=2) ;
for (i=0; i; i--, j*=2);
for (i = 0; i; i--, j *= 2);
No
space after increment/decrement
don't put a space after increment and decrement. increment after the value,
not before.
i --;
++j;
i--;
j++;
Don't increment, set or change
value of variable inside a function call
calc_x_y(i++, 2);
// if i is not a global:
calc_x_y(i, 2);
i++;
// if i is a global that calc_x_y() uses:
i++;
calc_x_y(i-1, 2);
if (i++)
a[i++] = 4;
set_x(i=3);
// if i is not a global:
i = 3;
set_x(i);
for
loops assign inside a statement
in for loops, when there is a function that gets the next element, it should
be done once (inside the step condition):
assign inside a statement:
for (i = 0, result = get_char(); result=='
'; result = get_char(), i++)
handle_result(result);
for (i = 0; (result = get_char())=='
'; i++)
handle_result(result);
truth value in
if/for/while
when assigning in a truth value (if for while), use parentheses. This helps
eliminating compilation warnings.
for (i = 0; result = get_result(); i++)
handle_result(result);
if (x = compute_num())
return x;
for (i = 0; (result = get_result()); i++)
handle_result(result);
if ((x = compute_num()))
return x;
string initialization and zero termination
in string initialization and zero termination, you must use 0
string[0] = ' ';
if (string[3]==' ')
...
*string = 0;
if (!string[3])
....
function return values
- in functions returning a pointer, return NULL on fail.
- in functions that only have success/fail, use 0 for success and -1 for
failure (instead of TRUE and FALSE).
- in functions with many error reasons, use negative values for the
reason.
-
functions returning and integer that is "small" and positive, return -1 if
fails. if 0 is an invalid success value, then you may choose to return 0
for failure.
-
in functions that can return any integer, you have two options:
- if its error is not important, then check if you can logically return
0 or anything else that will bring desired behaviour.
- if the error indication is important, then add another parameter to
pass the error.
-
functions that return boolean values (is_big, is_directory, is_download)
should return 0 for false and non 0 for true, according to standard K&R C.
(not to use FALSE and TRUE).
int do_load(void)
{
if (ioctl(image_fd, SIOC_LOAD, 1)<0)
return FALSE;
return TRUE; // action executed
}
int do_load(void)
{
if (ioctl(image_fd, SIOC_LOAD, 1)<0)
return -1;
return 0; // action executed
}
int is_loaded(void)
{
if (in_memory_count>=1)
return TRUE;
return FALSE;
}
int is_loaded(void)
{
if (in_memory_count>=1)
return 1;
return 0;
}
int is_loaded(void)
{
return in_memory_count>=1;
}
return ok ? (device_t *) ptr : NULL;
#define EFLASH_READ 1
#define EFLASH_WRITE 2
return -EFLASH_WRITE;
implement
error handling only once
implement error handling only once, by setting all variables to zero at the
begining, and performing a goto to exit the function. If no error handling is
required (i.e. no memory to release, no files to close, etc) - plain return
should be used
device_t *open_device(char *dev_name)
{
device_t *dev;
file *fp;
dev = malloc(sizeof(*dev));
if (!dev)
return null;
bzero(*dev);
dev->name = strdup(dev_name);
if (!dev->name)
{
free(dev);
return null;
}
dev->fp = fopen(dev->name);
if (!dev->fp)
{
free(dev->name);
free(dev);
return null;
}
fp = fopen(std_name)
if (!fp)
{
fclose(dev->fp);
free(dev->name);
free(dev);
return null;
}
fclose(fp);
return dev;
}
device_t *open_device(char *dev_name)
{
device_t *dev;
file *fp = null;
dev = malloc(sizeof(*dev));
if (!dev)
return NULL; // no error handling required
BZERO(*dev);
dev->name = strdup(dev_name);
if (!dev->name)
goto Error;
dev->fp = fopen(dev->name);
if (!dev->fp)
goto Error;
fp = fopen(std_name)
if (!fp)
goto Error;
goto Exit;
Error:
if (dev->name)
free(dev->name);
if (dev->fp)
fclose(fp);
free(dev);
dev = NULL;
Exit:
if (fp)
fclose(fp);
return dev;
}
Do not use goto for anything
other then error handling.
for (cnt = 0; cnt < sizeof(index_names)/sizeof(char *); cnt++)
{
struct stat sb;
strcpy(index_name + filename_len, index_names[cnt]);
// Check if the index file exists
if (stat(index_name, &sb)>=0)
{
...
hc->sb = sb;
goto Next;
}
}
return http_dir_handler(hc);
}
Next:
....
for (cnt = 0; cnt < sizeof(index_names)/sizeof(char *); cnt++)
{
struct stat sb;
strcpy(index_name + filename_len, index_names[cnt]);
// Check if the index file exists
if (stat(index_name, &sb)>=0)
{
...
hc->sb = sb;
break;
}
}
if (S_ISDIR(hc->sb.st_mode))
return http_dir_handler(hc);
}
....
naming conventions
code will be in UNIX notation. UNIX names should not include the data type,
rather the meaning of the information in the data.
int iCount;
char *szName;
int is_completed;
int8 data;
int16 vendor_id;
uint count;
void *buffer;
char *new_name;
char *name;
typedef struct {...} device_t;
int read_data_block(void);
void pci_detection(void);
checking function return values
functions that return int or a pointer will be checked without comparing, if
they return 0 or non 0.
if (strcmp(str, "exit")==0)
run_app();
if (!strcmp(str, "exit"))
run_app();
if (quit_app()==TRUE)
SendMessage(WM_QUIT);
if (quit_app())
SendMessage(WM_QUIT);
fp = fopen("test");
if (fp==NULL)
return NULL;
fp = fopen("test");
if (!fp)
return NULL;
char *buffer = locate_buffer();
if (buffer!=NULL)
fill_buffer(buffer);
char *buffer = locate_buffer();
if (buffer)
fill_buffer(buffer);
static
functions when possible
functions
when possible use static when declaring functions which are only in scope
for the file they're in. functions which are not declared static are
considered a part of the API. if init() is the only function calling
calc_init_time() then:
int init(void)
{
return calc_init_time();
}
int calc_init_time()
{
return 5;
}
int init(void)
{
return calc_init_time();
}
static int calc_init_time()
{
return 5;
}
variables
// inside c file
struct cmd {
char *name;
int param_num;
};
struct cmd commands[] = {
{"init", 1},
{"shutdown", 0},
};
// inside c file
struct cmd {
char *name;
int param_num;
};
static struct cmd commands[] = {
{"init", 1},
{"shutdown", 0},
};
allocating
when allocating or using a structre, use ZALLOC/calloc or BZERO its
elements.
try using BZERO instead of memset().
dev_t *dev = malloc(sizeof(dev_t));
locate_t locate;
memset(dev, 0, sizeof *dev);
memset(&locate, 0, sizeof locate);
dev_t *ZALLOC(dev);
locate_t locate;
if (!dev)
goto Error;
BZERO(locate);
Check constructor
initing
perfer to check constructor initing in same line of calling the constructor.
this allows variable re-use, and makes it more obvious the constructor may
fail.
// GOOD but not prefered:
FILE *fp;
if (!(fp = fopen("data"))
goto Exit;
// better:
FILE *fp = fopen("data");
if (!fp)
goto Exit;
// GOOD but not prefered:
char *s = strstr(list, "hello");
if (!s)
...;
// better:
char *s;
if (!(s = strstr(list, "hello")))
...;
macros
functions instead of
macros
try using functions instead of macros. in most cases there is no performance
problem.
#define CONVERT_TIME_TO_MILLI(t) (((t)->days*24*3600 + (t)->sec) * 1000)
int convert_time_to_milli(time_struct *t)
{
return (t->days*24*3600 + t->sec) * 1000;
}
macro names
macro names should normally be all upper case, with normal spacing as rest
of code
#define CONVERT_TIME_TO_MILLI( t ) (((t)->days*24*3600 + (t)->sec) * 1000)
#define CONVERT_TIME_TO_MILLI(t) (((t)->days*24*3600 + (t)->sec) * 1000)
#define CONVERT_TIME_TO_MILLI(t) (((t)->days*24*3600 + (t)->sec) * 1000)
#define CONVERT_TIME_TO_MILLI(t) (((t)->days*24*3600 + (t)->sec) * 1000)
macro multi arguments
using ## for macro multi arguments (x...) will result in a compilation error
when using gcc 3.3.x and up
#define IOW(func,a...) wfs_##func(##a)
#define IOW(func,a...) wfs_##func(a)
macros
with more than one statement
macros that are more than one statement long should be encapsulated by
do-while(0). this enables using them inside if-else statements:
// example usage:
if (cond)
DO_A_AND_B;
else
do_something_else();
#define DO_A_AND_B() { do_a(); do_b(); }
#define DO_A_AND_B() do { do_a(); do_b(); } while (0)
static functions in header instead of macros
if you need a function, but you don't want a library to link with, then you
can use static functions in the header file instead of macros
#define CREATE_HANDLE() (handle_t h, h = wd_open(), h==-1 ? NULL : h)
static handle_t create_handle(void)
{
handle_t h = wd_open();
if (h==-1)
return NULL;
return h;
}
static handle_t create_handle(void)
{
handle_t h;
if ((h = wd_open())==-1)
return NULL;
return h;
}
Don't use
forward declarations
don't use forward declarations unless they are necessary. Instead change the
order so the caller is below the callee.
void callee(...);
void caller(...)
{
callee();
}
void callee(...)
{
}
void callee(...)
{
}
void caller(...)
{
callee();
}
Prefer native c data
types instead of OS specific data types.
BYTE b;
DWORD w;
unsigned char b;
unsigned long b;
Double inclusion protection
at the begining of a file, add double inclusion protection, where the file
path and name is surrounted by two underscores before and after; a slash and
a dot are translated to an underscore.
#ifndef __UTIL_ZERR_H__
#define __UTIL_ZERR_H__
// the pkg/util/zerr.h content comes here
#endif
Files terminate
files should terminate with a carriage return
reason: compilers can ignore lines that are not terminated by a CR.
#endif
#endif
Nested #if
nested #if directives should not be indented (neither the # character nor
the directive itself, regardless of how complex they are).
#include
#ifdef UNIX
#include
#else
#include
#ifdef WINCE
#include
#endif
#endif
#include
#ifdef UNIX
#include
#else
#include
#ifdef WINCE
#include
#endif
#endif
void sleep_ms(int ms)
{
#ifdef WINDOWS
Sleep(ms);
#else
sleep(ms);
#endif
}
void sleep_ms(int ms)
{
#ifdef WINDOWS
Sleep(ms);
#else
sleep(ms);
#endif
}
You can put an #endif a comment telling to what if it belongs if there is
a large gap between the #if and its corresponding #endif.
#ifdef WINDOWS
int htonl(int i)
{
return (i << 16) & 0xffff0000 | (i >> 16) & 0xffff;
}
#endif // WINDOWS
#ifdef WINDOWS
int htonl(int i)
{
return (i << 16) & 0xffff0000 | (i >> 16) & 0xffff;
}
#endif
#ifdef CONFIG_RG_FIREWALL
// Lots of firewall code, that you really have to scroll down
// to see all of it.
#endif // CONFIG_RG_FIREWALL
enum
enum
should be in the
same line if they are very short
enum {STATUS_OK=DEVIOCTL_NOERROR, STATUS_FAIL=-1};
enum {
CMD_NONE=0,
CMD_END=1,
WP_WORD=14,
};
enum {
CMD_NONE = 0,
CMD_END = 1,
WP_WORD = 14,
};
enums should have
values attached
enum {
DO_RESET = 1,
DO_LOAD,
DO_SAVE,
};
enum {
DO_RESET = 1,
DO_LOAD = 2,
DO_SAVE = 3,
};
enum {
DO_RESET = 10,
DO_LOAD = 20,
DO_SAVE = 30,
};
all enum lines be
comma terminated
all enum lines be comma terminated - this makes the enum extensible.
only separate the last line, if it is meant to never be surpassed.
enum {
DO_RESET = 1,
DO_LOAD = 2,
DO_SAVE = 3
};
enum {
DO_RESET = 1,
DO_LOAD = 2,
DO_SAVE = 3,
};
enum {
BANDIT1 = 1,
BANDIT2 = 2,
ALI_BABA = 41
};
Spaces only after commas
enum in same line should have spaces only after commas
enum { DO_RESET = 1, DO_LOAD = 2, DO_SAVE = 3 };
enum {DO_RESET=1, DO_LOAD=2, DO_SAVE=3};
Put the pointer next to the
variable
char* strrev(char* s);
char *strrev(char *s);
Dynamic
allocation only when needed
use stack allocation for local variables of const size. use dynamic
allocation only when needed.
type_t *o = malloc(sizeof(*o));
...
free(o);
type_t o;
type_t *ZALLOC(o);
...
free(o);
// if possible:
type_t o = {0};
type_t o;
MZERO(o);
defined()
only use the defined() macro when you have a complex expression or in
#elif.
If you find that you do need to use the defined() macro for more than one
flag, see if the 2 flags can be grouped under another one new flag.
#ifdef CONFIG_CRAMFS_FS
#ifndef CONFIG_ARCH_IXP22X
cramfs_init();
#endif
#endif
#if defined(CONFIG_CRAMFS_FS)
cramfs_init();
#endif
#ifdef CONFIG_CRAMFS_FS
cramfs_init();
#endif
// since you really need both flags:
#if defined(CONFIG_CRAMFS_FS) || defined(CONFIG_NFS_FS)
cramfs_to_nfs_copy();
#endif
#ifdef CONFIG_CRAMFS_FS
cramfs_init();
#elif defined(CONFIG_NFS_FS)
nfs_init();
#endif
#ifdef SPECIFIC_OS
order
how to do and #ifdef SPECIFIC_OS
what comes first, the right
order is
#ifdef LINUX
.....
#elif defined(SOLARIS)
.....
#elif defined(VXWORKS)
.....
#elif defined(OS2)
.....
#elif defined(WIN95)
.....
#elif defined(WINNT)
.....
#elif defined(WINCE)
.....
#endif
C++ data members
names
in C++ classes give data members names starting with m_
class find_t
{
int m_index;
char *m_text;
};
functions
functions used in one C file: should be implemented static, and a
declaration in the C file should only be added if used before implemented.
(example: queue_locate_any()).
functions used out of the C file ('global'): should be declared in the H
file. (example: queue_locate_item() and queue_activate_operation()).
structures used in one C file: should be declared inside the C file.
(example: sched_operation_t).
a pointer to the structure is needed out of the C file: a forward
declaration should be in the H file, and the full decleration in the C file.
(example: sched_queue_t).
the structure's members are needed out of the C file: declare it in the H
file. (no example below).
// in H file
typedef struct sched_queue_t sched_queue_t;
sched_queue_t *queue_locate_item(char *name);
void queue_activate_operation(sched_queue_t *sched);
// in C file
typedef struct {
char *operation;
char *user;
} sched_operation_t;
sched_operation_t valid_operations[] = {
{"ls", "root"},
{"rm", "anonymous"},
{NULL, NULL}
};
struct sched_queue_t {
struct sched_queue_t *next;
char *name;
char *operation;
int expire;
};
sched_queue_t *the_queue;
static sched_queue_t *queue_locate_any(char *name)
{
sched_queue_t *search;
for (search = the_queue; search && strcmp(search->name, name);
search = search->next);
return search;
}
sched_queue_t *queue_locate_item(char *name)
{
sched_queue_t *search = queue_locate_any(name);
// check if already expired
if (expire>get_current_time())
{
queue_remove(search);
return NULL;
}
return search;
}
object oriented naming
the data structure should be the name of the object with _t at the end.
functions should all start with the object name, then operation starting
with a verb.
typedef struct {
the_objects_data_members;
} xxx_t;
// use _alloc and _free if it only allocates memory, and does not do
// "active" operations
xxx_t *xxx_alloc(initialization_param);
void xxx_free(xxx_t *xxx);
// use _open and _close if it does active stuff like call many functions,
// register events, IOCTLs etc...
xxx_t *xxx_open(initialization_param);
void xxx_close(xxx_t *xxx);
// use _init and _uninit if it does not allocate the xxx_t structure, only
// its sons - i.e. xxx_alloc can be a simple zalloc() while xxx_init
// can be a simple ZEROM(). xxx_uninit frees data structures that the xxx_t
// points to, without freeing xxx_t itself
void xxx_init(xxx_t *xxx, initialization_param);
void xxx_uninit(xxx_t *xxx);
// methods on the xxx object
char *xxx_get_by_index(xxx_t *xxx, int index);
int xxx_get_by_name(xxx_t *xxx, char *name);
char **xxx_get_name_list(xxx_t *xxx);
void xxx_set(xxx_t *xxx, char *name);
void xxx_set_nofail(xxx_t *xxx, char *name);
in_addr dev_if_ip_get(dev_if_t *dev);
// operation ('get_ip') must start with a verb ('get')
in_addr dev_if_get_ip(dev_if_t *dev);
linked lists
simple linked lists always have a 'next' variable as the first structure
member.
functions for list are
xxx_free() and xxx_list_free()
the xxx_yyy (xxx is object name and yyy is function name), for functions on
the object, NOT on list of objects.
the xxx_list_yyy is for functions on the list of objects (such as
xxx_list_add, xxx_list_remove).
// sample functions:
xxx_t *xxx_dup(xxx_t *p); // retunes a duplicated object
void xxx_copy(xxx_t *dst, xxx_t *src); // copy object's data
void xxx_free(xxx_t *p); // free the object
xxx_t *xxx_alloc(init_data....); // creates a new initialized object
void xxx_init(xxx_t *p, init_data....); // initializes an object
void xxx_uninit(xxx_t *p, init_data....); // un-initializes an object
// frees the list. list now is destroyed
void xxx_list_free(xxx_t *xxx_list);
// adds an object to the list
void xxx_list_add(xxx_t **xxx_list, xxx_t *new_elem);
Don't implement add and remove functions
normally, we should not implement add and remove functions (xxx_list_add and
xxx_list_remove). these should only be implemented if there is specific added
value (specific code) that needs to be done in addition to adding to the
list.
when scanning lists in order to add/remove elements, a pointer to pointer
should be used.
typedef struct file_t {
struct file_t *next;
char *name;
} file_t;
// frees a single file object
file_free(file_t *p)
{
if (p->name)
free(p->name);
free(p);
}
// frees the whole list of object
file_list_free(file_t *p)
{
while (p)
{
file_t *tmp = p->next;
file_free(p);
p = tmp;
}
}
free()
handles
NULL
free() also handles NULL, so no need for 'if ()' before it
if (str)
free(str);
free(str);
exit a
function with a negative value
to exit a function with a negative value, to indicate an error, and send a
log message, you may use the fact that zerr() returns negative value
// GOOD but a little long:
if (ioctl()<0)
{
zerr_f(LERR, "failed ioctl()");
return -1;
}
// GOOD short and neat:
if (ioctl()<0)
return zerr_f(LERR, "failed ioctl()");
constant
strings longer than one line
constant strings longer than one line should be closed on each line by a quote
and opened again on the next line. words should have the space after them on
the same line.
printf("Hello world, this is a long string that we want to print and is more than 80 chars long so we need to split it");
printf("Hello world, this is a long string that we want to print"
" and is more than 80 chars long so we need to split it");
printf("Hello world, this is a long string that we want to print "
"and is more than 80 chars long so we need to split it");
Dont use const char *
Don't use 'const char *' (or 'char const *') in code. It is impossible to
integrate code written with consts into a large system.
const char *gen_token(const char *seed);
// Return a static buffer - don't change.
char *gen_token(char *seed);
Zero parameters
functions
Functions that accept zero parameters should be defined as accepting
void
double get_time_ms();
double get_time_ms(void);
Compile time arrays
Compile time arrays should be terminated with a NULL (or -1 when 0 is valid)
element, and not by calculating the size of the the array using sizeof.
name_val_t arr[] = {
{"PPPoA", 1},
{"ETHoA", 2},
};
for (i = 0; i < sizeof(arr) / sizeof(arr[0]; i++)
elem_print(arr + i);
name_val_t arr[] = {
{"PPPoA", 1},
{"ETHoA", 2},
{NULL}
};
for (i = 0; arr[i].name; i++)
elem_print(arr + i);
Trivial
Trivial > >= < <= == !=
expressions should not have
spaces around them.
Trivial expressions examples: a_var, array[3].var[1], sizeof(xxx), (x +
1)
Pointers ->
are not counted as trivial
expressions for > >= < <=
, since its hard to read
x->y>z
, while its not hard to read
x->y==z
.
if (x > 5)
if (x>5)
if (x+1>5)
if (x+1 > 5)
if (f(x, y) > g(y, z))
if (f(x, y)>g(y, z))
if (x->y == 5)
if (x->y==5)
if (x->y>=5)
if (x->y >= 5)
Empty lines
Don't put empty lines between code inside functions. If you want to separate
code fragments, put a comment line.
for (i=0; i<5; i++)
printf(do_stuff);
if (x>5)
zerr(LERR, ...);
for (i=0; i<5; i++)
printf(do_stuff);
// check for invalid results
if (x>5)
zerr(LERR, ...);
Templates
Module foo in pkg/bar/foo.c & foo.h. All files should follow
this exact example.
#include "config.h" must be first in the *.c file to make sure the features
configuration affect all the rest of the files.
Header files must be self contained, i.e. - they must be able to compile
without relying on another include line to come before them.
Therefore #include "foo.h" must be immediately after to make sure foo.h
compiles stand alone without any dependency on includes before it.
_BEGIN_EXTERN_C and _END_EXTERN_C allow the code to link to C++.
pkg/bar/foo.c
template
// LICENSE_CODE ZON
#include "config.h"
#include "foo.h"
... put here minimal includes required by foo.c ...
... put here your code ...
pkg/bar/foo.h
template
// LICENSE_CODE ZON
#ifndef __BAR_FOO_H__
#define __BAR_FOO_H__
#include "config.h"
... put here minimal includes required by foo.h ...
_BEGIN_EXTERN_C
... put here functions, structures and other definitions ...
_END_EXTERN_C
#endif
#include "foo.h"
Use #include "foo.h" for headers in the same directory as the source
including them.
Use #include "path_to_foo/foo.h" for headers in other directories, where
path_to_foo is relative to root pkg directory.
Use #include <foo.h>
for external system files.
#include "stdio.h"
#include
#include "hash.h"
#include
#include "dhcp_lease.h" // we are in pkg/dhcp directory
#include "util/hash.h" // from pkg/util/hash.h
Temporary disabling
test
When temporary disabling test code that fail:
Do not indent the code of the disabled tests.
if (!running_on_valgrind) // XXX: yoni: fails on BAT
jtest_eq(...);
if (!running_on_valgrind) // XXX: yoni: fails on BAT
jtest_eq(...);
If it is only one
test
If it is only one test (one statement), then don't use { }
even
if the statement is written in 2 lines
if (!running_on_valgrind) // XXX: yoni: fails on BAT
{
jtest_run(xxx, yyy,
zzz);
}
if (!running_on_valgrind) // XXX: yoni: fails on BAT
jtest_run(xxx, yyy,
zzz);
Open {
on
the same if() line
// XXX: yoni: fails on BAT
if (!running_on_valgrind)
{
jtest_run(xxx, yyy, zzz);
jtest_run(xxx, yyy, zzz);
}
if (!running_on_valgrind) { // XXX: yoni: fails on BAT
jtest_run(xxx, yyy, zzz);
jtest_run(xxx, yyy, zzz);
}