Thursday, September 13, 2012

Writing better C/C++ code

ENABLING LINK -TIME OPTIMIZATION
-flto
https://stackoverflow.com/questions/20977741/stdvector-performance-regression-when-enabling-c11?noredirect=1#20977741
 
RESOURCES ON FUNCTION POINTERS
http://denniskubes.com/2013/03/22/basics-of-function-pointers-in-c/
http://milotshala.wordpress.com/2012/02/21/virtual-functions-in-c/
// forward declaration of our struct before it's definition
struct ClassA;
// The actual function table that holds function pointers.
typedef struct {
    void (*ClassA)(struct ClassA*); // the "constructor"
    void (*set)(struct ClassA*); // set function
    int (*get)(struct ClassA*); // get function
} ClassA_functiontable;
typedef struct ClassA {
    int data;
    ClassA_functiontable *vtable; // ClassA virtual method table
} ClassA;
// ClassA's function prototypes (forward declarations)
void ClassA_constructor(ClassA *this);
void ClassA_set(ClassA *this);
int ClassA_get(ClassA *this);
// Static array of the function table struct that contains ClassA's functions.
ClassA_functiontable ClassA_vtable = {ClassA_constructor,
                                  ClassA_set,
                                  ClassA_get };
                                   
// Implementation of functions and the constructor.                              
void ClassA_constructor(ClassA *this) {
    this->vtable = &ClassA_vtable;
    this->data = 10;
}
void ClassA_set(ClassA *this) {
    printf("ClassA is increasing\n");
    this->data++;
}
int ClassA_get(ClassA *this) {
    this->vtable->set(this);
    return this->data;
}
QT
To compile Qt related code with g++ (on Ubuntu 11.10+)
g++ -I /usr/include/qt4 -I /usr/include/qt4/QtCore -l QtCore test.cpp test.h -o test.test
qmake -project
Then fill in the resulting .pro file - much easier

C/C++
_Generic macros... awesome
http://www.robertgamble.net/2012/01/c11-generic-selections.html
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1404.htm

Set a single function to be called any time exit() is run
http://www.codecogs.com/reference/computing/c/stdlib.h/atexit.php

Ensuing discussion with good error checking macros
http://www.reddit.com/r/programming/comments/1856qx/how_did_i_miss_this_feature_in_c_so_far/

Excellent list of good compile time options
http://stackoverflow.com/questions/3375697/useful-gcc-flags-for-c

Example of parsing commandline arguments for C or C++ code
void ShowUsageAndExit()
{
     float VERSION=1.0;
     printf("Special sample code v%f\n",VERSION);
     printf("Usage: specsamp [options]\n");
     printf("\t -h .......... prints this help\n");
     exit(0)

int main(int argc, char** argv)
{
    int arg=1;
    while(arg<argc) {
        if(argv[arg][0] != '-') {
            show_usage_and_exit();
        }
        switch(argv[arg++][1])
        {
             case 'h':
                 ShowUsageAndExit();
                 break;
             default:
                 ShowUsageAndExit();
                 break;
         }
}

A quick sample of how to write C modules that will compile fine with a C++ compiler as well. For header file named test.h, something like this would be expected:
#ifndef _TEST_H_
#define _TEST_H_
#ifdef __cplusplus
extern "C" {
#endif

INCLUDES

CODE
CODE

#ifdef __cplusplus
}
#endif
#endif //_TEST_H_

Use a function like this to safely malloc: 
void* SafeMalloc(size_t sz)
{
   void *m = malloc(sz);
   if(!m)
   {
      fprintf(stderr, "Malloc failed for size %zd\n", sz);
      exit(1);
   }
   return m;
}


For passing fields to subfunctions, malloc() and free() is the way to go (or new and delete if using C++ != C++11)

GPGPU/CUDA
Avoiding branching for GPGPU, instead of:
if(cond(i)) 
    { out[i] = f(i); }
else
    { out[i] = g(i); }

Use this:
out[i] = f[i ] + cond[i] *(g[i]-f[i])

You compute everything - just as in the "standard" pattern - and you have another multiply-and-add, but you have only one commit to memory. It's sometimes better even in nested conditions.
(Not my words, originally commented by David on this post)

DEBUGGING TECHNIQUES
(gdb) define xxd
>dump binary memory dump.bin \$arg0 \$arg0+\$arg1
>shell xxd dump.bin
>end
(gdb) xxd &main 10
0000000: 0000 0000 0000 0000 0000 0000 4d8c a7f7 ............M...
0000010: ff7f 0000 0000 0000 0000 0000 c8d7 ffff ................
0000020: ff7f 0000 0000 0000

No comments:

Post a Comment