engin aydogan

's journal

RSS Feeds

  • Home
  • Old Site
  • Programming
  • STUFF I CODED

Macros in C/C++, the right way.

Dec 12th

Posted by engin in programming

When used appropriately macros are very useful, yet they are very easy to misuse. Before getting into cons and pros, first lets make sure if we really know what is a macro and how does it work.

Roughly there are three stages of compilation in C; preprocessing, compiling, linking. It really makes sense and it is very easy to understand, don’t think of this as a complex deal. We’ll mostly talk about the preprocessor stage in this post. As the name implies, this stage just pre-processes the source code before compiling it, it all happens prior to compiling and that’s it. Preprocessing includes defining some macros, and replacing each macro found in the source code with its value, so that it can be compiled. So get this right once and for all, macros are processed before compilation, they won’t be in the run-time code.

As an exercise you can use -E parameter of GCC, which will make it stop right after the preprocessing stage.

Now, let’s begin with a few examples;

#define ERROR_SEEK 152
if( errno == ERROR_SEEK )
{
    // Handle the error.
}

This directive defines a macro ERROR_SEEK. Preprocessor will replace every occurrences of ERROR_SEEK with 152 prior to compiling. So, the code that is going to be sent to compiler will have “if( errno == 152)” not the ERROR_SEEK because the compiler simply does not know what ERROR_SEEK is. Nothing fancy, dead simple. But it makes the code much more readable. Look at this example;

#ifdef __GNUC__
#define COMPILER "gcc"
#else
#define COMPILER "proprietary"
#endif

If __GNUC__ is defined somehow then every occurrences of COMPILER will be replaced with “gcc” and “proprietary” otherwise. Please note that this all happens before compilation, and this will not result in any executable code. In this special case __GNUC__ is defined by GCC itself. Though we can define a macro via #define directive in the source code, or with -D parameter of the compiler (which will work on most compilers).

Actually the name preprocessor says it all. All these preprocessor directives are pre processed before compilation. Makes sense uh ? Now I think we begin to understand the nature of macros/preprocessors.

Macros can be used to

  • Improve readability (ERROR_SEEK is much more meaningful than 152)
  • Improve maintainability (When you change ERROR_SEEK in one header, it will be replaced all over the source code)
  • Ensuring that a block of code is inlined (more on this later)

Though, if misused, the first two list items above will do  just the opposite :)

As for the possible disadvantages of preprocessors

  • Could make debugging harder as lines of source lines before and after the preprocessing will be different, so debugger can be confused while stepping the executable code and matching which source line of code it is.
  • It is easy to misuse preprocessors.
  • Could cause trouble to static code analyzers.

Now, possible misuse scenarios:

1. Operator precedence

The most common misuse scenario which you’ll see in almost every C book is this;

#define FOO_CONST 83+22
printf("%d\n", FOO_CONST * 5 ); // This macro will expand to 83 + 22 *  5, hence will result 193.

One could expect the result to be printed 525. But operator precedence would make the calculation 22 * 5 first, then add 83 to the result, so you’ll see 193 as a result instead of 525. Fixing this problem is easy;

#define FOO_CONST (83+22)
printf("%d\n", FOO_CONST * 5 ); // This macro will expand to (83+22) * 5, hence will result 525.

Enclosing the value of a macro is an easy way to ensure that they are evaluated in the right order.

2. Multiple statements

You can use multiple-statement macros to force inlining of a code block. Though note that this will increase the code size of your program. Anyway, the problem with the multiple-statements is a less known problem. Now, look at this.

#define HELLO(X) printf("Hello "); printf( X "\n" );

The problem with this code is, if you want to conditionally run this code with “if” this code will not do what you intend to do.

if(0)
    HELLO("world"); // You'd expect that this HELLO() is never "executed".

Above code will expand into

if(0)
    printf("Hello ");
printf( "world" "\n" );

As you can see in the above example only the first statement in the macro is conditionally executed, this is not what we intended for. Above code will always print “world\n”.

So, first thing comes to mind is to put them in curly brackets. Now let’s evaluate that.

#define HELLO(X) { printf("Hello "); printf( X "\n" ); }

Above code looks fine at first glance, but it will also introduce a sneaky bug that will result in compilation error. Now imagine above macro is used like this;

if(1)
    HELLO("world");
else
    HELLO("baby");

This will expand into;

if(1)
{
    printf("Hello ");
    printf("world" "\n");
}; // WE GOT ERROR HERE
else
{
    printf("Hello ");
    printf("baby" "\n");
};

So, here’s the trick which works perfectly. It is the do{} while(0) trick. OK, let’s see.

#define HELLO(X) do { printf("Hello "); printf( X "\n"); } while(0)

You can use this as you please, imagine the if else scenario.

if(1)
    HELLO("world");
else
    HELLO("baby");

This will expand into;

if(1)
    do { printf("Hello "); printf( "world" "\n" ); } while(0);
else
    do { printf("Hello "); printf( "baby" "\n" ); } while(0);

So do {} while(0) does not break when you place a semi-colon after it and also has a scope. So it’s a ideal for making sure your multiple-statements are executing as you expected.

Well, I guess that’s all I’ve got to say.

c, programming

PENSE – oPEN Simulation Environment

Dec 6th

Posted by engin in stuff i coded

Now, that I got a IDE/SATA USB case, I started looking at my very old HDDs. I found very old codes of mine, this is one of them. PENSE (oPEN Simulation Environment) was my thesis project. It is a framework which you can use to implement simulation easily. I wrote it in C++. Only dependency is GNU’s libmatheval to implement algorithms out of mathematical expressions easily. I even wrote documentation in LaTeX! :)

Anyway here’s libpense and pensedemo. Please note the autoconf masterpiece in the libpense :) it was a bitch to get it working but once it is working… well, it works. I remember compiling these codes on WIN32, Mac OS X and GNU/Linux without a single problem. Yes, I was young and stupid. I developed this on GNU/Linux :)

Oh, the documentation in LaTeX, PDF and the presentation in PPT format is available. Also there’s a reference manual for libpense, I guess I just had too much time :)

A-hem, and you have to excuse any lameness you can spot, since this is a 4-year old code ;)

A sample code from pensedemo;

        Environment env;
	Device::Source::PWM pwm( "pwm", &env );
	pwm.setOn( true );
	pwm.setFrequency( pwm_freq );

	Device::Source::VoltageSource vs( 0, 4.8, "voltage source", &env );
	vs.setOn( true );
	vs["output"] = 4.8;

	Device::Plant::DCMotor motor( "Maxon_118465", &env );
	motor.setLoad( "0.0" );
	motor["J_r"] = 0.0000000503;
	motor["k_n"] = 252.374609;
	motor["I_o"] = 0.029;
	motor["V"] = 0.0;
	motor["R"] = 2.16;

	Device::Controller::FuzzyLogic f( 3, "fuzzy logic controller", &env );

	f.setSetPoint( set_point );
	f.setInputDomainWidth( 5 );
	f.setOutputDomainRange( 0, 100 );

        // This is where we connect the devices together to form a feedback loop.
        // We connect the PWM controller to the Voltage Source so that PWM can turn
        // the VS on and off. Then we connect the voltage source to the DC Motor, so
        // that it can, well, run. Then we connect the angular velocity parameter of the
        // motor to the Fuzzy Logic controller, so that it can adjust the PWM controller
        // and control the speed of the motor.
	connect( &pwm, "output", &vs, "on" );
	connect( &vs, "output", &motor, "V" );
	connect( &motor,"w", &f, "input" );
	connect( &f, "output", &pwm, "duty" );
c, fuzzy logic

Some declaration details for pointers in C/C++

Dec 3rd

Posted by engin in programming

First of all let’s remember what a pointer is. A pointer is an address pointing to an object. “Address” term is open for debate, some pedantic assess would argue against it.

So let’s start giving examples.

const char* str ="Foo";
str[0] = 'B'; // error: assignment of read-only location
str = "Bar"; // Perfectly OK

So, it is obvious that first line declares str as n pointer pointing to a constant object and the object is not modifiable but the pointer itself is.

Let’s review another example.

char * const str = "Foo";
str[0] = 'B'; // Perfectly OK (See the node below)
str = "Bar"; // error: assignment of read-only variable

Here we can see that the declaration tells compiler that the pointer value (address) is constant but the object it is pointing to can be modified. Please note that even though the above assignment “str[0] = ‘B’” will compile just fine, it will most probably result in a segmentation fault during runtime since your compiler will most likely put it in read only memory region.

Now let’s make another example.

const char * const str = "Foo";
str[0] = 'B'; // error: assignment of read-only location
str = "Bar"; // error: assignment of read-only variable

This declaration tells the compiler that neither the object the pointer is pointing to can be modified, nor the pointer value (address) itself. i.e. nothing is modifiable :)

Conclusion

So, we can conclude that qualifiers (const, volatile) that are placed before the * applies to the object the pointer is pointing to, and qualifiers placed after the * applies to the pointer value itself, i.e. the address.

So we can have weird looking declaration like this one:

extern volatile const char * volatile const str = "Foo";

I know it looks a bit unusual but it is perfectly valid.

Note: For hardware programming volatile keyword is a must. If you don’t know what it is, read this article at wiki.answers.com first. Here’s the backup, just in case.

c, embedded
«12
  • Recent Posts

    • JQuery with template engines which uses dollar sign $
    • Chrome UTF-8 bug
    • zero-configuration connectivity on embedded computers
    • ExternalInterface performance on different browsers
    • Cross-domain data-push methods compared
  • Archives

    • August 2010
    • July 2010
    • April 2010
    • March 2010
    • February 2010
    • January 2010
    • December 2009
  • Tags

    c chrome dhcp embedded enda firefox flash flex fuzzy logic plc programming uip
  • Categories

    • programming
    • stuff i coded
    • web
  • Pages

    • About
Mystique theme by digitalnature | Powered by WordPress
RSS Feeds XHTML 1.1 Top