Howtos and Tips

System

For details on functions search in the man page (man <function-name> or man -a <function-name> if there is also a unix command with same name), or search the web.

Catching signals

⇒ C and C++.

You can catch ctrl-c or other signals, for example to clean up things before to quit.

#include <signal.h>
 
void function_upon_sig (int sig __attribute__((unused)))
{
  // write what you want to do here
  exit(0);
}
 
int main()
{
  signal(SIGINT, function_upon_sig); // ctrl-c
  signal(SIGTERM, function_upon_sig);
  signal(SIGHUP, function_upon_sig);
  signal(SIGALRM, function_upon_sig);
 
}

You can see a complete list of all signals here.

You should only use “async-signal safe” functions in the handler to avoid deadlocks (async-signal safety is stronger than thread safety, because the main program is completely interrupted until the handler has terminated). For example, printf is not safe, but write is, so you should write text on the terminal using write(STDOUT_FILENO, text, text_length); (more details here).

You can also change the signals actions with the sigaction function.

Timer

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

will trigger signal SIGALRM x seconds later that you can catch (see catching_signals).

If you need automatic repetition and/or sub-second precision, you can use:

#include <sys/time.h>
int setitimer(int whichtimer, const struct itimerval *value, struct itimerval *ovalue);

Waiting event

Monitor multiple file descriptors.

#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

Posix Threads

#include <pthread.h>
 
void *threadFunction(void *threadid)
{
	printf("%d: Hello World!\n", threadid);
	pthread_exit(NULL);
}
 
int main (int argc, char *argv[])
{
	pthread_t threadId;
	int threadData = 42;
	if (pthread_create(&threadId, NULL, threadFunction, (void *)threadData) != 0)
	{
		printf("thread creation failed");
		exit(1);
	}
	return 0;
}

FIXME join sem etc

Change program owner

pwd = getpwnam("cyril");
if (pwd) 
{
	setgid(pwd->pw_gid);
	setuid(pwd->pw_uid);
}

But it doesn't really work to start shell commands, you should use sudo too:

system("sudo -u cyril <command>);
system("sudo -u cyril /bin/sh -c '<command1>; <command2>');

Formatting IOs (iomanip)

⇒ C++

#include <iomanip>

for everything in this section.

Color

std::cout << "normal text, "  << "\033[1;33m" 
          << "colored text, " << "\033[1;00m"
          << "normal text" << std::endl;
Code Effect Code Effect
\033[1;00m normal white
\033[1;29m bold white \033[0;29m normal white
\033[1;30m bold grey \033[0;30m normal grey
\033[1;31m bold red \033[0;31m normal red
\033[1;32m bold green \033[0;32m normal green
\033[1;33m bold yellow \033[0;33m normal yellow
\033[1;34m bold blue \033[0;34m normal blue
\033[1;35m bold purple \033[0;35m normal purple
\033[1;36m bold cyan \033[0;36m normal cyan

Floating point precision

double x = 32.14554;
std::cout << "Double with 3 significant digits : " 
          << std::setprecision(3) << x 
          << std::endl; // 32.1

Alignment

std::cout << std::setw(10) << "hello"; // "hello     "
std::cout << std::setfill('.') << std::setw(10) << "hello"; // "hello....."
std::cout << std::right << std::setw(10) << "hello"; // "     hello"

White spaces

To get all characters while they are white spaces.

std::cin >> std::ws >> buffer; // "\r\n pouet" -> "pouet"

C/Cpp Preprocessor

To stop the compilation and print a message :

  #error Cannot compile

To just print a message :

  #warning Possible problem

To get a macro argument as a string :

  #define ASSERT(x) if (x == NULL) printf("Pointer %s NULL", #x);

Macro with variable argument count (C99 only) :

  #define ERROR(msg, ...) fprintf("ERROR:%s:%d# ", __FILE__, __LINE__, ## __VA_ARGS__);

You can also use the PRETTY_FUNCTION but it is not standard:

  #define ERROR(msg, ...) fprintf("ERROR:%s:%d %s# ", __FILE__, __LINE__, __PRETTY_FUNCTION__, ## __VA_ARGS__);

Get the type of an argument :

  #define abs(x) ({ typeof(x) xx=(x); xx>0 ? xx : -xx; })

Conversions with string

From * to string

⇒ C++

#include <sstream>
std::ostringstream oss;
oss << 565;
std::cout << oss.str() << std::endl;

⇒ C & C++

#include <stdio.h>
char s[128];
sprintf(s, "%d", 565);

From string to *

⇒ C & C++

#include <stdlib.h>
int i = atoi("562");
long l = atol("4500294");
double f = atof("4.546643");

#define in compiler command

You can define names for the preprocessor from the command line (or the makefile) instead of the source file (#define name). It can be very useful.

Command Equivalent in source file
-D name #define name
-D name=value #define name value
-U name #undef name
g++ foo.cc -o foo -D BAR=3

Function pointers

The full test program is available here

Normal fn

int fonction(double x, bool b); // declaration of the function
int (*pf)(double,bool);         // declaration of the pointer to function
pf = &fonction;                 // initialization of the pointer
(*pf)(9,true);                  // call of the function through the pointer

Using typedef:

int fonction(double x, bool b);    // declaration of the function
typedef int (*fnIdb)(double,bool); // declaration of pointer type
fnIdb pf = &fonction;              // declaration and initialization of the pointer
(*pf)(9,true);                     // call of the function through the pointer

Static member fn

Static member functions behave the same way than normal functions.

class ClasseS { public: static int fonction(double x, bool b); }; // declaration of the function
int (*psf)(double,bool);                                         // declaration of the pointer to the function
psf = &ClasseS::fonction;                                        // initialization of the pointer
(*psf)(5,true);                                                  // call of the static member function through the pointer

Non virtual member fn

Member functions have a hidden parameter (a pointer to this), so the pointer needs an object to call the function. If the member function is non virtual, the address of the member function is the same for all objects.

class Classe { public: int fonction(double x, bool b); }; // declaration of the function
int (Classe::*pcf)(double,bool);                          // declaration of the pointer to function
pcf = &Classe::fonction;                                  // initialization of the pointer
Classe classe; (classe.*pcf)(9,true)                      // call of the member function through the pointer

Virtual member fn

The syntax is the same as for non virtual member functions, and the pointer points to the place in the object where the address of the function is stored, so that it always points to the right function.

class Classe { public: int fonction(double x, bool b); };
class Classe2 : public Classe { public: int fonction(double x, bool b); };
int (Classe::*pcvf)(double,bool);    // declaration
pcvf = &Classe::fonction;            // initialization
Classe *classe1 = new Classe(), *classe2 = new Classe2();
(classe1->*pcvf)(9,true)             // calls Classe::fonction
(classe2->*pcvf)(9,true)             // calls Classe2::fonction

Cast overloading

Cast from

This is done with constructors :

class FixedPoint
{
  unsigned int data;
 public:
  FixedPoint() { data = 0; }
  FixedPoint(int x) { data = x<<8; }
  Fixedpoint(double x) { data = (unsigned int)(x * (1<<8)); }
};
 
double pi;
FixedPoint pif;
pi = 3.14;
pif = pi; // it works, FixedPoint(double) is called for the cast

Cast to

The syntax is simple :

class FixedPoint
{
  unsigned int data;
 public:
  ...
  operator double() { return data / (double)(1<<8); }
};
 
double pi;
FixedPoint pif(3.14);
pi = pif; // it works, double() is called for the cast

Template cast

Imagine the following situation :

template <typename T>
class Pixel
{
  T r,g,b;
 public:
  template <typename N> inline Pixel<T>& operator=(Pixel<N> &pix) 
    { r=pix.r; g=pix.g; b=pix.b; return *this; }
};
 
Pixel<unsigned char> pix1;
Pixel<int> pix2;
pix2 = pix1; // it works, because operator= and cast are simultaneously overloaded that way

Of course it works only if there is a possible cast from N to T. You can do the same with all operators (+,+= …).

Operators overloading

It is painful to remember all declarations of operators overloading, then here they are :

#include <iostream> // for stream operators
 
class Object
{
  int a,b;
 public:
  Object(int a, int b) : a(a), b(b) {}
  // You MUST overload copy constructor and operator= if you allocate memory in your object
  Object(Object &o) : a(o.a), b(o.b) {}
  Object& operator= (const Object &o)       { a=o.a; b=o.b; return *this; }
  // this is for +, but idem for all homogeneous binary operators : -,*,/, ...
  Object  operator+ (const Object &o) const { return Object(a+o.a, b+o.b); } 
  Object& operator+=(const Object &o)       { a+=o.a; b+=o.b; return *this; }
  // this is for *, but idem for all heterogeneous binary operators : /,<<,>> ...
  Object  operator* (int x) const { return Object(a*x, b*x); } 
  Object& operator*=(int x)       { a*=x; b*=x; return *this; }
  // stream operators should not be members, declare it friend to access protected data
  friend std::ostream& operator<<(std::ostream& os, const Object &o);
  friend std::istream& operator>>(std::istream& is, Object &o);
};
 
//.cpp
std::ostream& operator<<(std::ostream& os, const Object &o)
{
  os << ...;
  return os;
}
 
std::istream& operator>>(std::istream& is, Object &o)
{    
  while (is >> ...) ...
  return is;
}

Operators precedence

Precedence Operator Name Associativity
17 :: :: scope resolution / global R/L
16 () () function call / value construction L/R
[] subscripting L/R
. -> member selection L/R
++ -- post increment/decrement R/L
15 () type cast R/L
sizeof size of type or object R/L
& * address of / dereference R/L
~ ! bitwise complement / logical not R/L
+ - unary plus and minus R/L
++ -- pre increment/decrement R/L
new delete delete[] create / destroy / destroy array R/L
14 .* ->* member selection L/R
13 * / % multiply / divide / modulo L/R
12 + - plus / minus L/R
11 << >> bit shifting L/R
10 < <= > >= comparison L/R
9 == != comparison L/R
8 & bitwise and L/R
7 ^ bitwise exclusive or L/R
6 | bitwise inclusive or L/R
5 && logical and L/R
4 || logical inclusive or L/R
3 ?: conditional expression R/L
2 = += -= *= /= %= assignments R/L
<<= >>= &= ^= |=
1 throw throw exception R/L
0 , comma L/R

Types

Type Size Range Precision
char 1 byte -128 to 127 1
unsigned char 1 byte 0 to 255 1
short 2 bytes -32768 to 32767 1
unsigned short 2 bytes 0 to 65535 1
int 4 bytes -2 147 483 648 to 2 147 483 647 1
unsigned int 4 byte 0 to 4 294 967 295 1
long (int) 4 bytes = int 1
unsigned long (int) 4 bytes = unsigned int 1
long long (int) 8 bytes -9.22337E+18 to 9.22337E+18 1
unsigned long long (int) 8 bytes 0 to 1.84467E+19 1
enum 4 bytes = int 1
float 4 bytes 3.4E-38 to 3.4E+38 6 digits
double 8 bytes 1.7E-308 to 1.7E+308 15 digits
long double 10 bytes 1.2E-4932 to 1.2E+4932 18 digits
programming/howtos-tips.txt · Last modified: 2014/04/16 18:07 by cyril
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0