A
arnuld
I have written C coding guidelines for my company. All of those
guidelines I have learned from this newsgroup. So I thought it will a be
good idea if you people can have a look and advise on improvement or
anything else:
==== The Compilation Phase ====
The default compiler that comes with Linux is gcc and System Programming
team of Phonologies uses the same. In Phonologies, we work as a part of a
team. A project is divided into difference pieces/sections and each piece
is given to each team member to code. You have to work as an independent
programmer to code that piece. All pieces are joined together to form a
complete software and they joined and then re-edited and tested many
times before finally labeled as "ready to release". To do that work
properly, we have some guidelines that reduce the overall bugs,
production time and of course the tension generated by future problems.
Whenever you pass a piece of code to your fellow team-mate, you pass it
after compiling and running it successfully on your machine. You will
use either "gcc -ansi -pedantic -Wall -Wextra" or "gcc -std=c99 -pedantic
-Wall -Wextra" to compile your programs. If you are interested in knowing
what *exactly* all of those flags do, please refer to the gcc manual. At
no point of time you will ever pass the program to anyone in the team
without using these flags. These flags will tell you about lots of bugs
and run-time problems before they even surface. It is your responsibility
to remove the bugs and clear the program of all the run-time anomalies of
your own programs, not of your team's. There are no Sir(s) in
Phonologies, there are no attitudes like "yes boss", or "Sir, you are
genius". At Phonologies we are a family, one family member will not bear
the consequences of the problems created by other member just because
that *other* member is unwilling to do hard-work. (We don't work like the
obsolete USSR). Your code, Your responsibility.
==== Team Spirit ====
When the pieces of software are combined and being tested and then if
some bugs come up and they will surely come up, then it will not be like
""Arnuld wrote this code and therefore I will not solve this bug"". We
are team, so please behave like a team. The reply ""Sumit wrote this
code, so he knows better about it and he can fix it sooner than me"" is
very different from the former. Now if somehow, Sumit is working on
fixing some other important issues and handling some other tasks which
have priority then you will fix this bug. Yes..., you can go and talk to
him (when he will have free time) about his design, code and the way he
programmed this piece but since he does not have time, it is you who will
fix the current bug. One of our ex-employees *Saurabh Nirkhey* worked
hard on flourishing this team-spirit.
==== Practices that are Frowned Upon ====
" void main() ": "main()" will always return int. You will never use
"void main()". If you are still using "void main()" and wonder about this
guideline then trust me you are still living in academic world. Wake up
and deal with the reality, use "int main(void)" or "int main(int argc,
char* argv[])". Every C program returns a value to the shell that helps
in knowing the reasons of success or failure or sudden crash or even
semantic errors. When you write "void main()" you *specifically* tell
the shell that you are more intelligent than "Donald Knuth" and do not
need to know the cause of the problem, that you are exceptionally
intelligent and you don't need any help from the compiler to solve the
problem. I am sorry, we do, not everyone is as intelligent as you, we
need to identify and fix the problems without wasting any time or
efforts. Hence we need "int main(void)" or "int main(int argc, char*
argv)". You may wonder that we use "int main(void)" rather than "int main
()". Its because, in C, an empty parenthesis means you can pass unlimited
number of arguments to the function. To tell the C compiler that you are
not expecting an argument you write void in those parenthesis. (In C++ an
empty parenthesis means no arguments are being passed, C and C++ are not
same languages, remember this)
"Not Function Parameters": Always check function parameters for NULL
values. You must check for unexpected values before you start to use
them. Any code that does not do so will not pass Phonologies Coding
Standards and hence will be returned back to you in no time and with no
mercy. Be a good neighbor.
"Sir, Arrays and Pointers are same": Dream on.
=== gcc Warnings ===
Here we will discuss about gcc compile-time warnings. Here is the real-
life run of "app_voiceXML.c" that we use with [[http:"www.asterisk.org/ |
Asterisk]].
my-Test.c: In function wait_for_answer:
my-Test.c:962: warning: implicit declaration of function
senddialevent
my-Test.c:966: warning: implicit declaration of function get_cid_name
my-Test.c:966: warning: passing argument 3 of ast_set_callerid makes
pointer from integer without a cast
my-Test.c:1133: warning: implicit declaration of function
onedigit_goto
my-Test.c: In function VoiceXML_exec:
my-Test.c:1261: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1272: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1284: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1295: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1306: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1320: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1354: warning: unused variable end
my-Test.c:1354: warning: unused variable content
my-Test.c:1534: warning: unused variable dummy
my-Test.c:1653: warning: too many arguments for format
my-Test.c:1847: warning: passing argument 3 of ast_call makes integer
from pointer without a cast
my-Test.c:1879: warning: implicit declaration of function
send_ipx_transfer_result
my-Test.c:1932: warning: implicit declaration of function sprint
my-Test.c:1852: warning: unused variable peerflag
my-Test.c:1774: warning: unused variable who
my-Test.c:1773: warning: unused variable f
my-Test.c:1252: warning: unused variable cat
my-Test.c: At top level:
my-Test.c:2101: warning: return type defaults to int
my-Test.c:2101: warning: no previous prototype for
send_ipx_transfer_result
my-Test.c: In function recv_ack_initial_sdp:
my-Test.c:736: warning: control reaches end of non-void function
my-Test.c: In function send_ipx_transfer_result:
my-Test.c:2117: warning: control reaches end of non-void function
my-Test.c: At top level:
my-Test.c:419: warning: print_proto_packet defined but not used
my-Test.c:517: warning: recv_ack_prepare defined but not used
my-Test.c:764: warning: send_ipx_prepare defined but not used
You will never ever discard the gcc warning. Warnings like:
* "passing argument 3 of ast_call makes integer from pointer without a
cast" almost always results in run-time [[http:"en.wikipedia.org/wiki/
Logic_error | semantic error]] that can take days and even months to
solve.
* "control reaches end of non-void function " will result in problems
like return value of a function was going to be passed to some other
function or to be assigned to some variable but function did not return
anything which will again cause run-time semantic error.
* "send_ipx_prepare defined but not used" . You can ignore it but you
will not. The point is, if there are too many unused variables then some
important warning, for which very few words appear on the screen, can be
lost between the mess of these unused variables. So you have to remove
all the unused variables before you pass this file to the teammate. BTW,
if you are not using a variable whats the point of defining it ? ..
Don't give me the crap that it can be used in future. In future if it
some change/edit is going to be made then we *have to* open and read the
file anyway. We can add your unused variable at that time. Things change
a lot in future, not to mention your own expansion as a programmer which
can force you to rewrite some of your programs.
==== Memory Problems ====
" malloc(), calloc()": In C we use "calloc()" or "malloc()" to allocate
memory. Please avoid them most of the time as using "malloc()" is a CPU
intensive task. When you want to work efficiently, you use static memory.
Hence we advocate the use of Static arrays rather than "malloc()". Of
course, when you need "caloc()" or "malloc()", you definitely have to use
it. Whenever you use memory allocation you will always check the return
value against NULL. Many Segmentation Faults can be avoided by using this
principle. When a Segmentation Fault comes, it does not tell you from
where it came. Out of all those 16 source files and in those 6000 lines
of code, you have no idea which one produced the Segmentation Fault.
Checking for a NULL can avoid those bitter times that every programmer
does not want to have in his life. A Segfault is PITN (Pain In The Neck),
it kills time, resources, spreads confusion, is the devotee of a Satan,
is the Diabetes of C program, is the Angel of Death. Please check your
return value if you want to keep your program alive and well. A simple
NULL check takes around 60 seconds to type but it can save days and even
months of debugging. If you count the number of seconds a team of C
Programmers has taken to solve Segfaults, they add up to years of
lifetime and its not an exaggeration.
"Memory Leaks": First make sure you have called "free()" for every "malloc
()" (unless there is some special reason on not to). Then even if your
program is eating up memory, use "valgrind": *valgrind* "--leack-
check=full --show-reachable=yes executable". "valgrind" is unavoidable
when several people are writing code for same piece of software. If you
need to use "valgrind" for your program which has only 6 C source files,
where every expression was written by you , then your programming habits
are much worse. You get that because don't understand at least one of
them: "arrays", "pointers", "malloc()" or "Data Structure" you are using.
==== Return values from functions ====
Every function who is doing an important work will always return some
value. Functions who just print information to some file or to the stdout
need not to return anything (though you may do that). The problem that we
are trying to solve is, some variable was supposed to get some value from
the function but function returns void and then that variable can wrongly
be set to some garbage value (technically known as uninitialized value)
which create havoc on your output. This can save you from a lot of
trouble. We are not saying functions can not return void, yes they can
and they are very few. Its a style of programming that helps debugging
and solving problems.
===== Work Environment =====
System Programmers who either blame someone else or or use social or
diplomatic skills to hide behind their mistakes will not be tolerated. We
strive to have a casual atmosphere so that people can code and use their
time effectively, we do our best to give programmers a sane environment
so that they can use their skills without wasting either time or efforts
and produce quality code in the end. Such kind of work environment is
very difficult to find. So please lets keep it that way or make it better.
==== One Last Piece of Advice ====
Never *ever* underestimate gcc warnings. Don't blame the compiler for
your wrongdoings. A compiler always does what you tell it to do, it is
never wrong.
guidelines I have learned from this newsgroup. So I thought it will a be
good idea if you people can have a look and advise on improvement or
anything else:
==== The Compilation Phase ====
The default compiler that comes with Linux is gcc and System Programming
team of Phonologies uses the same. In Phonologies, we work as a part of a
team. A project is divided into difference pieces/sections and each piece
is given to each team member to code. You have to work as an independent
programmer to code that piece. All pieces are joined together to form a
complete software and they joined and then re-edited and tested many
times before finally labeled as "ready to release". To do that work
properly, we have some guidelines that reduce the overall bugs,
production time and of course the tension generated by future problems.
Whenever you pass a piece of code to your fellow team-mate, you pass it
after compiling and running it successfully on your machine. You will
use either "gcc -ansi -pedantic -Wall -Wextra" or "gcc -std=c99 -pedantic
-Wall -Wextra" to compile your programs. If you are interested in knowing
what *exactly* all of those flags do, please refer to the gcc manual. At
no point of time you will ever pass the program to anyone in the team
without using these flags. These flags will tell you about lots of bugs
and run-time problems before they even surface. It is your responsibility
to remove the bugs and clear the program of all the run-time anomalies of
your own programs, not of your team's. There are no Sir(s) in
Phonologies, there are no attitudes like "yes boss", or "Sir, you are
genius". At Phonologies we are a family, one family member will not bear
the consequences of the problems created by other member just because
that *other* member is unwilling to do hard-work. (We don't work like the
obsolete USSR). Your code, Your responsibility.
==== Team Spirit ====
When the pieces of software are combined and being tested and then if
some bugs come up and they will surely come up, then it will not be like
""Arnuld wrote this code and therefore I will not solve this bug"". We
are team, so please behave like a team. The reply ""Sumit wrote this
code, so he knows better about it and he can fix it sooner than me"" is
very different from the former. Now if somehow, Sumit is working on
fixing some other important issues and handling some other tasks which
have priority then you will fix this bug. Yes..., you can go and talk to
him (when he will have free time) about his design, code and the way he
programmed this piece but since he does not have time, it is you who will
fix the current bug. One of our ex-employees *Saurabh Nirkhey* worked
hard on flourishing this team-spirit.
==== Practices that are Frowned Upon ====
" void main() ": "main()" will always return int. You will never use
"void main()". If you are still using "void main()" and wonder about this
guideline then trust me you are still living in academic world. Wake up
and deal with the reality, use "int main(void)" or "int main(int argc,
char* argv[])". Every C program returns a value to the shell that helps
in knowing the reasons of success or failure or sudden crash or even
semantic errors. When you write "void main()" you *specifically* tell
the shell that you are more intelligent than "Donald Knuth" and do not
need to know the cause of the problem, that you are exceptionally
intelligent and you don't need any help from the compiler to solve the
problem. I am sorry, we do, not everyone is as intelligent as you, we
need to identify and fix the problems without wasting any time or
efforts. Hence we need "int main(void)" or "int main(int argc, char*
argv)". You may wonder that we use "int main(void)" rather than "int main
()". Its because, in C, an empty parenthesis means you can pass unlimited
number of arguments to the function. To tell the C compiler that you are
not expecting an argument you write void in those parenthesis. (In C++ an
empty parenthesis means no arguments are being passed, C and C++ are not
same languages, remember this)
"Not Function Parameters": Always check function parameters for NULL
values. You must check for unexpected values before you start to use
them. Any code that does not do so will not pass Phonologies Coding
Standards and hence will be returned back to you in no time and with no
mercy. Be a good neighbor.
"Sir, Arrays and Pointers are same": Dream on.
=== gcc Warnings ===
Here we will discuss about gcc compile-time warnings. Here is the real-
life run of "app_voiceXML.c" that we use with [[http:"www.asterisk.org/ |
Asterisk]].
my-Test.c: In function wait_for_answer:
my-Test.c:962: warning: implicit declaration of function
senddialevent
my-Test.c:966: warning: implicit declaration of function get_cid_name
my-Test.c:966: warning: passing argument 3 of ast_set_callerid makes
pointer from integer without a cast
my-Test.c:1133: warning: implicit declaration of function
onedigit_goto
my-Test.c: In function VoiceXML_exec:
my-Test.c:1261: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1272: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1284: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1295: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1306: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1320: warning: assignment discards qualifiers from pointer
target type
my-Test.c:1354: warning: unused variable end
my-Test.c:1354: warning: unused variable content
my-Test.c:1534: warning: unused variable dummy
my-Test.c:1653: warning: too many arguments for format
my-Test.c:1847: warning: passing argument 3 of ast_call makes integer
from pointer without a cast
my-Test.c:1879: warning: implicit declaration of function
send_ipx_transfer_result
my-Test.c:1932: warning: implicit declaration of function sprint
my-Test.c:1852: warning: unused variable peerflag
my-Test.c:1774: warning: unused variable who
my-Test.c:1773: warning: unused variable f
my-Test.c:1252: warning: unused variable cat
my-Test.c: At top level:
my-Test.c:2101: warning: return type defaults to int
my-Test.c:2101: warning: no previous prototype for
send_ipx_transfer_result
my-Test.c: In function recv_ack_initial_sdp:
my-Test.c:736: warning: control reaches end of non-void function
my-Test.c: In function send_ipx_transfer_result:
my-Test.c:2117: warning: control reaches end of non-void function
my-Test.c: At top level:
my-Test.c:419: warning: print_proto_packet defined but not used
my-Test.c:517: warning: recv_ack_prepare defined but not used
my-Test.c:764: warning: send_ipx_prepare defined but not used
You will never ever discard the gcc warning. Warnings like:
* "passing argument 3 of ast_call makes integer from pointer without a
cast" almost always results in run-time [[http:"en.wikipedia.org/wiki/
Logic_error | semantic error]] that can take days and even months to
solve.
* "control reaches end of non-void function " will result in problems
like return value of a function was going to be passed to some other
function or to be assigned to some variable but function did not return
anything which will again cause run-time semantic error.
* "send_ipx_prepare defined but not used" . You can ignore it but you
will not. The point is, if there are too many unused variables then some
important warning, for which very few words appear on the screen, can be
lost between the mess of these unused variables. So you have to remove
all the unused variables before you pass this file to the teammate. BTW,
if you are not using a variable whats the point of defining it ? ..
Don't give me the crap that it can be used in future. In future if it
some change/edit is going to be made then we *have to* open and read the
file anyway. We can add your unused variable at that time. Things change
a lot in future, not to mention your own expansion as a programmer which
can force you to rewrite some of your programs.
==== Memory Problems ====
" malloc(), calloc()": In C we use "calloc()" or "malloc()" to allocate
memory. Please avoid them most of the time as using "malloc()" is a CPU
intensive task. When you want to work efficiently, you use static memory.
Hence we advocate the use of Static arrays rather than "malloc()". Of
course, when you need "caloc()" or "malloc()", you definitely have to use
it. Whenever you use memory allocation you will always check the return
value against NULL. Many Segmentation Faults can be avoided by using this
principle. When a Segmentation Fault comes, it does not tell you from
where it came. Out of all those 16 source files and in those 6000 lines
of code, you have no idea which one produced the Segmentation Fault.
Checking for a NULL can avoid those bitter times that every programmer
does not want to have in his life. A Segfault is PITN (Pain In The Neck),
it kills time, resources, spreads confusion, is the devotee of a Satan,
is the Diabetes of C program, is the Angel of Death. Please check your
return value if you want to keep your program alive and well. A simple
NULL check takes around 60 seconds to type but it can save days and even
months of debugging. If you count the number of seconds a team of C
Programmers has taken to solve Segfaults, they add up to years of
lifetime and its not an exaggeration.
"Memory Leaks": First make sure you have called "free()" for every "malloc
()" (unless there is some special reason on not to). Then even if your
program is eating up memory, use "valgrind": *valgrind* "--leack-
check=full --show-reachable=yes executable". "valgrind" is unavoidable
when several people are writing code for same piece of software. If you
need to use "valgrind" for your program which has only 6 C source files,
where every expression was written by you , then your programming habits
are much worse. You get that because don't understand at least one of
them: "arrays", "pointers", "malloc()" or "Data Structure" you are using.
==== Return values from functions ====
Every function who is doing an important work will always return some
value. Functions who just print information to some file or to the stdout
need not to return anything (though you may do that). The problem that we
are trying to solve is, some variable was supposed to get some value from
the function but function returns void and then that variable can wrongly
be set to some garbage value (technically known as uninitialized value)
which create havoc on your output. This can save you from a lot of
trouble. We are not saying functions can not return void, yes they can
and they are very few. Its a style of programming that helps debugging
and solving problems.
===== Work Environment =====
System Programmers who either blame someone else or or use social or
diplomatic skills to hide behind their mistakes will not be tolerated. We
strive to have a casual atmosphere so that people can code and use their
time effectively, we do our best to give programmers a sane environment
so that they can use their skills without wasting either time or efforts
and produce quality code in the end. Such kind of work environment is
very difficult to find. So please lets keep it that way or make it better.
==== One Last Piece of Advice ====
Never *ever* underestimate gcc warnings. Don't blame the compiler for
your wrongdoings. A compiler always does what you tell it to do, it is
never wrong.