Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternatives to preprocessor directives

I am engaged in developing a C++ mobile phone application on the Symbian platforms. One of the requirement is it has to work on all the Symbian phones right from 2nd edition phones to 5th edition phones. Now across editions there are differences in the Symbian SDKs. I have to use preprocessor directives to conditionally compile code that are relevant to the SDK for which the application is being built like below:

#ifdef S60_2nd_ED
  Code
#elif S60_3rd_ED
  Code
#else
  Code

Now since the application I am developing is not trivial it will soon grow to tens of thousands of lines of code and preprocessor directives like above would be spread all over. I want to know is there any alternative to this or may be a better way to use these preprocessor directives in this case.

Please help.

like image 907
ardsrk Avatar asked May 13 '09 11:05

ardsrk


People also ask

Is preprocessor directive necessary in C?

The C Preprocessor is not a part of the compiler, but is a separate step in the compilation process. In simple terms, a C Preprocessor is just a text substitution tool and it instructs the compiler to do required pre-processing before the actual compilation.

What are the two most common kinds of preprocessor directives?

There are 4 Main Types of Preprocessor Directives: Macros. File Inclusion. Conditional Compilation. Other directives.

Why macros are not good?

Whether you're eating a protein, carbs, or fat, aim high. There is a big difference between good macros for your body and bad macros for your body. Eating bad macros increases the likelihood of disease, obesity and energy depletion.


2 Answers

Well ... That depends on the exact nature of the differences. If it's possible to abstract them out and isolate them into particular classes, then you can go that route. This would mean having version-specific implementations of some classes, and switch entire implementations rather than just a few lines here and there.

You'd have

  • MyClass.h
  • MyClass_S60_2nd.cpp
  • MyClass_S60_3rd.cpp

and so on. You can select which CPP file to compile either by wrapping the entire inside using #ifdefs as above, or my controlling at the build-level (through Makefiles or whatever) which files are included when you're building for various targets.

Depending on the nature of the changes, this might be far cleaner.

like image 194
unwind Avatar answered Sep 22 '22 15:09

unwind


I've been exactly where you are.

One trick is, even if you're going to have conditions in code, don't switch on Symbian versions. It makes it difficult to add support for new versions in future, or to customise for handsets which are unusual in some way. Instead, identify what the actual properties are that you're relying on, write the code around those, and then include a header file which does:

#if S60_3rd_ED
    #define CAF_AGENT 1
    #define HTTP_FILE_UPLOAD 1
#elif S60_2nd_ED
    #define CAF_AGENT 0
    #if S60_2nd_ED_FP2
        #define HTTP_FILE_UPLOAD 1
    #else
        #define HTTP_FILE_UPLOAD 0
    #endif
#endif

and so on. Obviously you can group the defines by feature rather than by version if you prefer, have completely different headers per configuration, or whatever scheme suits you.

We had defines for the UI classes you inherit from, too, so that there was some UI code in common between S60 and UIQ. In fact because of what the product was, we didn't have much UI-related code, so a decent proportion of it was common.

As others say, though, it's even better to herd the variable behaviour into classes and functions where possible, and link different versions.

[Edit in response to comment:

We tried quite hard to avoid doing anything dependent on resolution - fortunately the particular app didn't make this too difficult, so our limited UI was pretty generic. The main thing where we switched on screen resolution was for splash/background images and the like. We had a script to preprocess the build files, which substituted the width and height into a file name, splash_240x320.bmp or whatever. We actually hand-generated the images, since there weren't all that many different sizes and the images didn't change often. The same script generated a .h file containing #defines of most of the values used in the build file generation.

This is for per-device builds: we also had more generic SIS files which just resized images on the fly, but we often had requirements on installed size (ROM was sometimes quite limited, which matters if your app is part of the base device image), and resizing images was one way to keep it down a bit. To support screen rotation on N92, Z8, etc, we still needed portrait and landscape versions of some images, since flipping aspect ratio doesn't give as good results as resizing to the same or similar ratio...]

like image 30
Steve Jessop Avatar answered Sep 22 '22 15:09

Steve Jessop