int64_t vs long long

Ξ February 21st, 2010 | → 0 Comments |
Programming |, , , , |

This last monday morning, a colleague enters in my office and asked for my… how should I put it… let’s say technical advise.

This time the discussion was about using int64_t and double in some deprecated code involving type casts and trunc of doubles into integers.
This discussing made me research a bit about C and C++ data types regarding integers, since somewhere along the way I listened to something like “I was told to use int64_t because long long is architecture dependent”. It struck deep.

Let’s start with some simple clarifications:

  •  int, or signed int, type must contain at least 16 bits (since the standard mandates that in must support values ranging from -32,767 to +32,767)
  •  long, or long int or signed long int, type must contain at least 32 bits (since the standard mandates that in must support values ranging from -2,147,483,647 to 2,147,483,647)
  •  long long, or long long int or signed long long int, type must contain at least 64 bits (since the standard mandates that in must support values ranging from -9,223,372,036,854,775,807 to 9,223,372,036,854,775,807). Note that this data type was first defined by C99 standard.

Regarding int64_t, as it seems, C99 standard defines a header files called stdint.h as part of the C standard library, that contains portable definitions for integer types. Portable in the sense of explicitly stating the number of bits used to represent a given integer. The definitions are in the form of intN_t and uintN_t, for N bit integers and unsigned integers, respectively. This way the programmer can ensure that, whatever the wordsize used by the processor, the right range of values can be represented. The standard garantees that the widths for these types must be ≥ N.

However well supported by modern compilers, take notice that stdint.h is not officially in the latest C++ standard (know by C++03).

Looking again at the statement that aroused my curiosity, what is the relation between int64_t and long long?
Well, they represent the same thing in most architectures! Both int64_t and long long first got defined by C99 standard, but int64_t definition ensures that 64 bits are used for represent the integer value while with long long at least 64 bits must be used.

For example, some architectures represent long and int with the same number of bits (32 bits). The standard only requires at least N bits. :-)

 

Variadic C/C++

Ξ September 27th, 2009 | → 0 Comments |
Programming |, , |

Did you ever wanted to create your own printf and never knew how to make your functions or methods take a variable number or arguments? Then this test if for you…

If you ever took the chance to read the manual page for printf functions, I may noticed the following definition for the this C standard variadic function (yes, thats’s how functions/methods that a variable number of arguments):

int printf(const char *format, …);

All the magic is done by that ’strange’ three points. Let’s see how one can one them. Imagine you what to implement a logging interface using the following variadic function (note: level_t is an enumerate of the available log levels):

void log(level_t level, const char *format, …);

This allows you to add log entries like:

log(FATAL, “Exiting to unknown problem.”);
log(ERROR, “Unable to open file %s.”, filename);
log(WARNING, “Falling to default configuration.”);
log(INFORMATION, “Computation at step %d : %s.”, step, description);
log(DEBUG, “Running iteration %d.”, i);


After understanding that the ’strange’ three points represent a va_list which contains the list of arguments. The way to access the contents of the three points is as follow:

void log(level_t level, const char *format, …)
{
  va_list args                // 1. create the list of pointers to unnamed arguments
  va_start(args, format);     // 2. initialize the list of pointers to arguments
                              //    note: the second argument must be the last of fixed arguments
 
printf( “Level %d”, level );// 3. use printf to display the required information
  while( !va_end(args) )      // 4. iterate over available arguments, until the end of the list
  {
    const char *str

       = va_arg( args, char * ); // 5. access the argument value
                                              //    note: it is necessary to provide the type of the argument

    printf( “%s\n”, str );       // 6. display the selected argument
  }

  va_end( args )              // 7. cleanup the argument list
}

This is one way to do it, but you can implement the same function based of a printf sibling, called vprintf which allows you to pass the va_list directly to printf. This also solves the problem with the cast required at steo 5. of the previous example. So, this is the resulting implementation:

void log(level_t level, const char *format, …)
{
  va_list args;
  va_start(args, format);
 
printf( “Level %d”, level );
  vprintf( format, args );    // notice the use of vprintf
  va_end( args );
}

There is also the possibility to provide the developer with variadic MACROS. See here for more details.

 

Handling SIGSEGV Signal

Ξ May 9th, 2008 | → 0 Comments |
Development |, , , , |

Soon or later, your Linux developed C/C++ code will generate a SISEGV signal and your application will miserably crash. This signal is generated when a program tries to read or write outside the memory that is allocated for it, or to write memory that can only be read. (Actually, the signals only occur when the program goes far enough outside to be detected by the system’s memory protection mechanism.) The name is an abbreviation for “segmentation violation”.

In order to improve your program, and terminate in a controlled way, you can register a custom function to handle such signal. The following example shows the leave function that is called whenever a SIGSEGV signal is launched.

    #include

    #include

    void leave( int s ) {
        std::cout << "FATAL: Leaving due to SIGSEGV." << std::endl;
        exit( s );
    }

    int main() {
        // Register SIGSEGV handler!
        signal( SIGSEGV, leave );

        // originate a SIGSEGV
        double array[20];
        std::cout << array[10000] << std::endl;

        return 0;

    }