Menu-Submenu

Informative Tips in C

Informative Tips

  1. strtok_r() v/s strtok() in C?


strtok()
- Used for string parsing and extracting tokens
- Not thread safe, as it used a global variable inside
- when called for the first time takes in the string to be parsed as one of the argument and subsequent calls need just NULL to be passed in place of the string. The initial string passed to strtok gets assigned to a global variable which is referenced in subsequent call of strtok. This can cause issue in multithreaded environment if string passed is a shared string.

strtok_r()
- Instead use strtok_r, in multithreaded requirement, which is the reentrant version of strtok
- so is thread safe.​


  1. The evaluation order of function arguments is Unspecified


Function parameters are not evaluated in a defined order ("from Right to Left") in C.
The C standard gives implementations full freedom to evaluate them in:
1) Left to Right or
2) Right to Left or
3) Any other magical order
Also, the implementation is not needed to specify which ordering it follows.

For example, output of below printf() function call will vary based on compiler.
printf("%d %d %d\n", printf("1\n"), printf("22\n"), printf("333\n"));
Same is applicable for
printf(“%d %d %d\n”, i++, i++, i);

References:
C99 Standard 6.5.2.2 Function calls --- Para 10:
The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.
C99 Standard 3.19: --- unspecified behavior
behavior where this International Standard provides two or more possibilities and imposes no requirements on which is chosen in any instance.
EXAMPLE An example of unspecified behavior is the order in which the arguments to a function are evaluated.

This allow the compiler to re-order the evaluation of the operands adds more room for optimization.
Better code can be generated in the absence of restrictions on expression evaluation order



  1. printf() warped into a macro for different formats with variable arguments


#define PRINT_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__);
#define PRINT_LOG_OPTIONAL(fmt, ...) printf("[PID=%d] [TID=%p] %s():%d "fmt"\n", getpid(), pthread_self(), __FUNCTION__, __LINE__, ## __VA_ARGS__);

Works for different formats of printf()
  1. PRINT_LOG("This is plain log.\n");    //In place of print("This is plain log.\n");

  1. int i;
char name[10];
...
PRINT_LOG("This is formatted log with %d %s.\n", i, name);    //In place of print("This is formatted log with %d %s.\n", i, name);

  1. char* strLog = NULL;
strLog = malloc(sizeof(char)*100);
strcpy(str, "This is runtime generated log.\n");
PRINT_LOG(strLog);    //In place of print(strLog)

Extension to handle the trailing comma: The ‘##’ token paste operator has a special meaning when placed between a comma and a variable argument.
The variable argument is Left Out when the macro is used without any variable argument, then the comma before the ‘##’ will be deleted. This does not happen if the token preceding ‘##’ is anything other than a comma.

Additional References:
  • "Overloading Macro on Number of Arguments" https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments
#define FOO2(x,y) ...
#define FOO3(x,y,z) ...
#define FOO4(x,y,z,w) ...

To achieve like following,
#define FOO(x,y) FOO2(x,y)
#define FOO(x,y,z) FOO3(x,y,z)
#define FOO(x,y,z,w) FOO4(x,y,z,w)

Need to perform as following,
#define GET_MACRO(_1,_2,_3,_4,NAME,...) NAME
#define FOO(...) GET_MACRO(__VA_ARGS__, FOO4, FOO3, FOO2)(__VA_ARGS__)

FOO(a,b,c,d)          # expands to FOO4(a,b,c,d)