Showing posts with label Preprocessor. Show all posts
Showing posts with label Preprocessor. Show all posts

Saturday, August 11, 2012

Conditional Inclusion in ANSI C

Let us assume that you have a program that will run on multiple platforms. For each platform you have an API which defines the functions that you will call in your program.

Example Scenario:
Your platforms are Windows, Unix, BSD and Mac. The headers for the platform specific operations are:
-Windows: windows_api.h
-Unix: unix_api.h
-BSD: bsd_api.h
-Mac: mac_api.h

Here's an example on how to implement conditional inclusion for this case:
#define PLATFORM_WINDOWS 0
#define PLATFORM_UNIX    1
#define PLATFROM_BSD     2
#define PLATFORM_MAC     3

/*Defines the system as UNIX*/
#define SYSTEM PLATFORM_UNIX

#if SYSTEM == PLATFORM_WINDOWS
    /*Uses the Windows platform API*/
    #include"windows_api.h"
    #define Shutdown()         WinQuit();
    #define ShowMessage(s)     WinShowMsg(s)
#elif SYSTEM == PLATFORM_UNIX
    /*Uses the Unix platform API*/
    #include"unix_api.h"
    #define Shutdown()         XQuit();
    #define ShowMessage(s)     XShowMsg();
#elif SYSTEM == PLATFORM_BSD
    /*Uses the BSD platform API*/
    #include"bsd_api.h"
    #define Shutdown()         BsdQuit();
    #define ShowMessage(s)     BsdShowMsg();
#elif SYSTEM == PLATFROM_MAC
    /*Uses the MAC platform API*/
    #include"mac_api.h"
    #define Shutdown()         MacQuit();
    #define ShowMessage(s)     MacShowMsg();
#else
    /*Triggers a compilation error*/
    #error Unknown platform
#endif

int main(void)
{
    /*The functions will use the UNIX API*/
    ShowMessage("Hello world!");
    ShutDown();
    return 0;
}

Avoiding Multiple Header Inclusion in ANSI C

Let us assume that you have 2 header files a.h and b.h and one source file main.c.

The files are in following relation:
Double-inclusion scenario
Let assume that this is the initial content of the files:
The content of b.h:
/*b.h*/
typedef enum
{
    val1 = 1,
    val2,
    val3
}EValues;
The content of a.h:
/*a.h*/
#include"b.h"

const int resource2 = val1+val2;
The content of main.c:
/*main.c*/
#include"a.h"
#include"b.h"
#include<stdio.h>

int main(void)
{
    printf("val1: %d\nval2: %d\nResource %d",val1,val2,resource2);
    return 0;
}
If you try to build the program you will encounter redeclaration errors:
../b.h:13:5: error: redeclaration of enumerator ‘val1’
../b.h:13:5: note: previous definition of ‘val1’ was here
../b.h:14:5: error: redeclaration of enumerator ‘val2’
../b.h:14:5: note: previous definition of ‘val2’ was here
../b.h:15:5: error: redeclaration of enumerator ‘val3’
../b.h:15:5: note: previous definition of ‘val3’ was here
../b.h:16:2: error: conflicting types for ‘EValues’
../b.h:16:2: note: previous declaration of ‘EValues’ was here
The solution for this problem is to use include guards.
#ifndef _HEADER_IDENTIFIER_
#define _HEADER_IDENTIFIER_

/*Header code*/

#endif
In order to make the program work corectly you will have to add an include guard to a.h and b.h:
The content of b.h:
/*b.h*/
#ifndef _B_H_
#define _B_H_

typedef enum
{
    val1 = 1,
    val2,
    val3
}EValues;

#endif
The content of a.h:
/*a.h*/
#ifndef _A_H_
#define _A_H_

#include"b.h"

const int resource2 = val1+val2;

#endif
The content of main.c:
/*main.c*/
#include"a.h"
#include"b.h"
#include<stdio.h>

int main(void)
{
    printf("val1: %d\nval2: %d\nResource %d",val1,val2,resource2);
    return 0;
}
/*Output
val1: 1
val2: 2
Resource 3
 */

Related Posts Plugin for WordPress, Blogger...