Hi, I am currently trying to get my code support two different type of LCD display, the only difference is the hardware level driver, so condional compilation directive has to be introduced. #ifdef DISPLAY_1 void display_driver() { // do one thing } #else void display_driver() { // do another thing } #endif However I don't want change the directive in the code, I would like to do it in the IDE, I guess it should be under project\option\C51, any one know how to do it ? Thanks in advance. Daniel
Options for Target ==> C51 ==> Preprocessor Symbols ==> 'Display_1'
to reduce the amount of repeated typing, you could consider:
void display_driver() { #ifdef DISPLAY_1 // do one thing #else // do another thing #endif }
An alternative to conditional compilation would be to have two separate source files, each of which defines one version of display_driver(). You then use the 'Include in Build' file option to choose which one actually gets compiled... You could create two Targets for your project to manage this (you could also control the conditional-compilation with multiple Project Targets).
to reduce the amount of repeated typing, you could consider: even easier re typing in main .h file
#define DISPLAY_1 // comment out if not display 1
"even easier re typing" No - you miss the point. I was talking about the amount of typing in the two definitions of his driver - not the amount of typing to set the #define !!
Oh, well. I usually "get excited" when reducing typing is mentioned. It gives you more time to type comments. Erik
It's often useful to have a positive check to be sure that someone actually selected a driver option, rather than just falling into an else clause due to lack of a choice. #if defined(DRIVER_1) #elif defined(DRIVER_2) #else #error "DRIVER_? must be defined" #endif It's tempting to try to define a "variable" for this sort of thing, but unfortunately the preprocessor doesn't really allow "strings": #if LCD_DRIVER == LCD_TYPE_0 #elif LCD_DRIVER == LCD_TYPE_1 #else #error "LCD_DRIVER must be defined" #endif You can do this if you're sure to include some #defines everwhere LCD_DRIVER might be used: #define LCD_TYPE_0 0 #define LCD_TYPE_1 1 Otherwise, all the undefined symbols just devolve to 0 and you get unexpected results. For this sort of job I personally would be more likely to bind at link time. That is, write two driver.c files and add the correct one to the project, as was mentioned earlier. Conditional compilation rapidly leads to unreadable preprocessor spaghetti, and also tends to degrade the usefulness of search / diff / merge tools.
For this sort of job I personally would be more likely to bind at link time. That is, write two driver.c files and add the correct one to the project, as was mentioned earlier. Conditional compilation rapidly leads to unreadable preprocessor spaghetti, and also tends to degrade the usefulness of search / diff / merge tools. This is not pantyhose (one size does not fit all) I have files with conditional compile and I have "parallel files". The trouble with "parallel files" is that, if they are very similar, they are likely to have the same bugs. The risk with "parallel files" is that you may miss a global fix in one of them. That said, if you end up an awful lot of #ifdefs your code will be flearidden for that reason. One way I have found to be very effective is using macros. One example: In a program I "inherited" there was 113 #ifdefs for kicking the watchdog since the software drove 2 different hardwares. Replacing all this with a macro KICK_THE_PUPPY reduced the #ifdefs to ONE (in the macro). one methgod I have usewd for handling "parallel files" is to include them all in the library. function for sign 1: (void) fusgn1(void) function for sign 2: (void) fusgn2(void) .... then, in module I oddly enough have named "select" I have #if (SIGNTYPE == 1) #define fusgn fusgn1 #elif (SIGNTYPE == 1) #define fusgn fusgn2 .... and main() call fusgn Erik just some ways to do it.
The trouble with "parallel files" is that, if they are very similar If the files are very similar, I agree. Drivers for two different devices, on the other hand, aren't likely to have any similarities other than the names and parameters of the API. Often in such a case, you've discovered a natural interface in the design. The one file that originally seemed to be a single coherent module really has subcomponents. You can then factor the two parallel files into one common file, plus a few helper / utility functions that encapsulate the true differences. You'd have one common file with the common code and two auxiliary files, of which you link one. At some point, the changes are so minor or the granularity of the change so small that it's easier to do conditional compilation rather than refactor the code.
"It's often useful to have a positive check to be sure that someone actually selected a driver option, rather than just falling into an else clause due to lack of a choice." Very good advice. #define LCD_TYPE_0 0 #define LCD_TYPE_1 1 While we're on the subject of Defensive Programming, values 0 and 1 are best avoided - as these are prime candidates for default values if something is just defined without actually being assigned a proper value (eg, on a command line).
Good point. Zero is particularly bad since undefined symbols evaluate to zero.
"Otherwise, all the undefined symbols just devolve to 0 and you get unexpected results." Although, unlike some other compilers I have used, Keil does issue a diagnostic in this situation.