Smart coding




Writing an efficient code is very important for a good programmer but writing a readable code, which is easily understandable to any new programmer, is equally important. A good code should never give an unexpected output, and it should not crash during execution. Below are given some tips, which every C programmer should follow.

Naming convention:

Every variable, function and even file should be given a meaningful name. While naming variables, one should properly use under score (_) and a mix of upper and lower case letters e.g. it is better to name a variable StudentName or student_name rather than studentname.

Documentation:

Put brief description about functionality in comments before every section of code. Put comments in beginning of file about its functionality, history, author, and owner. Every function should also be documented with a brief description about its functionality, parameters and return datum.

Code partitioning:

Generally beginner starts coding with small programs and writes whole program in a single function. Putting everything in a single function is bad practice, it leads to difficulty in debugging any issues. One should properly divide code in logical functions, files, and modules.

Error Handling and variable initialization:

To avoid any unexpected behavior and crash during execution of a program, one should handle errors properly. Every variable must be initialized to a default value or zero/NULL. Every function should carefully check its parameters and should return a well defined error code.

Free memory that you allocate:

Always free memory allocated by you, which is no longer in use to avoid any memory leak. Try to free memory in the same function, where it was allocated until unless it is required for later use. If it is required for later use then write a cleanup function to free it. Ensure de-allocation of memory on every path to return from the function, which allocates it.

int test_allocate(int par)
{
    char *str = (char *)malloc(10);
    /* Params check */
    if(0 == par)
    {
        free(str); /* deallocate before return */
        return (-1);
    }
    /* do something */
    free(str);
    return (0);
}


It safer to use strncpy() than strcpy():

It is always safer to use strncpy() than strcpy() as you know size of your source and destination strings. strcpy() doesn’t takes care of size of destination, it copies each character from source strings till ‘\0’ termination. It may leads over flow (out of bound) at destination string. While using strncpy(), always remember that it doesn’t append ‘\0’ character at the end of destination string.

Never use multiple loops:

Never use multiple loops, if it can be accommodated in single loop. 


for(i=0; i<10; i++)
{
    do_xxx();
}
for(i=0; i<10; i++)
{
    do_yyy();
}

It would be better to do: 



for(i=0; i<10; i++)
{
    do_xxx();
    do_yyy();
}

Two factors impacts performance of a loop: one is that if you do a lot of work in the loop, it might not fit into your processor's instruction cache. In this case, two separate loops may actually be faster as each one can run completely in the cache.
The other factor is that if you are accessing same data objects in both of your loops, using a single loop may be faster because the most recently used data object can be kept in the CPU cache. If you have two loops, you may not be able to take advantage of that caching.


Smart Comparision:

Whenever comparing two data objects for equality and if one of them is a constant/literal then use constant/literal as first operand of == e.g. use

( <Literal/Constant> == <Variable> )


rather than

(<Variable> == <Literal/Constant>)

In this way you can catch error for unintended assignments if you miss one ‘=’ sign like
( 0 = i)

Don’t play with const:

You must know that it is possible to modify a variable declared as const. Here is an example that demonstrates the power of pointers which is dangerous in this case.

#include<stdio.h>
int main()
{
    const char a='A';
    char *b;
    b = (char *) &amp;a;
    *b = 'c';
    printf("%c\n",a);
    return 0;

}

You should not modify value of const in your program, it violates the const rule and may produce some wrong results in other part of program.

Protect pointer in function parameters:

If you don’t want a data object to be modified by a function, use const parameters to protect such data object. This case is applicable when you are passing pointer of any data object as parameter in any function.

Example:

test_method(const int *para)
{
    *para = 10; //Compiler Error, because it is a constant.
}

The reason you want to pass a const variable into a function is to guarantee the function is not able to change the value that the pointer is pointing at.

It also helps readability because by reading the pass-in parameter of the function, you knew that the const char *value will not change.


Dangling Pointers:

Always reset a pointer to NULL, after de-allocating the memory pointed by this. It makes sure that you do not use a dangling pointer. For example:

free(device_list);
device_list=NULL


Now if any attempt made to read/write the memory location pointed by device_list will result in crash of the program, while in other case device_list will have a reference of an anonymous location, reading and writing to an anonymous location is invalid, and it is very hard to find such error.


Use Pointer as function parameter:

Always use pointer to pass any structure object as parameter in a function. Since every parameter will be pushed on stack and if you pass object as parameter instead of it’s pointer, it will occupy more space on stack, which may lead to stack overflow.
Example:

test_method(struct employee_data *new_emp);

Don't modify too many variables in single statement:

Always try to modify only 1 variable in a statement. If required then you can modify maximum three variables for better readability.
Example:

A=(b++) + (++c); //OK: all the three variables modified

but avoid

A=(b++) + (++c) + (--d);


Don’t modify any variable more than once in a single statement:

You should not modify a variable more than once in a single statement. Compiler behavior is not defined by ANSI C for such scenario; it may produce different result on different compilers.
Example:

A = (b++) + (++b); //NOT OK: b has been modified twice

A = ++A; //NOT OK: A has been modified twice

No comments:

Simple theme. Powered by Blogger.