We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hello everyone,
So, I am working with an 8051W core processor (with OTP, once again, that's a whole other discussion) and I'm pretty maxed out on code space and looking to trim it down a bit. I need to check the functionality of some of my interrupts so I've had to create code that looks like this:
void main (void) { DiagMode = 0; /* Loop for standard/hardware diagnostics mode */ if ((DiagMode == 0) || (DiagMode == 2)) { while (1) { // Insert code here }; /* Loop forever */ } /* Loop for simulation/software diagnostic mode */ else if (DiagMode == 1) { while(1) { decimator2_ISR(); // Insert code here }; /* Loop forever */ } }
So if I wanted to use the code in simulation mode, I set DiagMode = 1. When I go to burn the chip, I set it equal to 0 (or 2 if I'm doing some hardware diagnostics, I have various case statements throughout the code that run only if DiagMode = 1 or 2).
Currently, if I want to cut down the code I have, I can comment out any unnecessary code portions (anything with DiagMode = 1, etc). I was wondering if there was a way to set my code to build the code differently if it is being used in simulation mode and when I compile it to hex (or set DiagMode to 0), the portions in code with DiagMode set to 1 are not built into the hex code, saving space.
I apologize if what I'm asking for is confusing. Realistically, it probably isn't possible but I figure if anyone would know how to do something along these lines (or has a better alternative), this would be the place to go.
Let me know when you get the chance. Thanks!
I don't do it because i worry about "giving code". I do it because I want to show a skeleton showing the concept without any extra noise around.
Remember that threads on this forum are read by people who find the threads using search engines at a much later time. They don't care about your specific source code. But they may care about the concept that is covered in the thread.
Ok - sorry for the confusion here.
If the code uses #if defined(symbol) or #if symbol == xx or #ifdef(symbol) then there is a contract between you and the compiler vendor (based on the C language standard) that the compiler/preprocessor/linker combination will completely ignore lines that are within a block that where the condition isn't fulfilled.
So you can write:
#define SKIP_DEBUG #if !defined(SKIP_DEBUG) here I can have whatever random text I want (that doesn't look like some important preprocessor directive like #else, #endif, ... and the compiler will totally ignore if this is valid C or not. It will be stripped away before the C compiler starts to figure out what code you have. #endif
But you will get errors if you write:
int skip_debug = 1; if (!skip_debug) { I want the compiler to ignore this. But the compiler will scream blue murder because this is random text within the C source code. }
Ok. So what about "correct" code, but you want to save space.
int charlie(int a,int b) { int skip_debug = 1; if (!skip_debug) { printf("I'm in debug mode now. So lots of nice extra printouts.\n"); printf("I'm in function charlie() and time of day is '%s'.\n",my_time_of_day(tmpbuf)); } return a+b; }
The compiler will process every single line as C code. Any syntax error will be caught. The compiler can see that skip_debug is always non-zero. The compiler can know that the print() statements can never be activated. The compiler _may_ decide to not generate any code for that block and compile your source as if you had:
int charlie(int a,int b) { return a+b; }
I say _may_. There is no "must". The language standard allows the compiler to figure out that the if block can never be activated, and that the expression "skip_debug" don't have any side effect.
But there are no contract between you and the language standard that guarantees the optimization. There _may_ be a contract between you and the language standard that the compiler should optimize away the code.
So try same thing agan, but we move the variable include_debug outside the function.
int skip_debug = 1; int charlie(int a,int b) { if (!skip_debug) { printf("I'm in debug mode now. So lots of nice extra printouts.\n"); printf("I'm in function charlie() and time of day is '%s'.\n",my_time_of_day(tmpbuf)); } return a+b; }
Now, the life is way harder for the compiler. include_debug is a global variable, and the above code isn't enough to prove if any other code within the full program may modify the value of skip_debug to zero.
So unless the compiler/linker have very advanced code for performing full (cross)module optimization, it must include the code even if _you_ know the the variable is always zero and the code should never be run.
So then we have the mixed case.
#define skip_debug 1; int charlie(int a,int b) { if (!skip_debug) { printf("I'm in debug mode now. So lots of nice extra printouts.\n"); printf("I'm in function charlie() and time of day is '%s'.\n",my_time_of_day(tmpbuf)); } return a+b; }
This gets processed as:
int charlie(int a,int b) { if (!1) { printf("I'm in debug mode now. So lots of nice extra printouts.\n"); printf("I'm in function charlie() and time of day is '%s'.\n",my_time_of_day(tmpbuf)); } return a+b; }
Now, it is easier again for the compiler to notice the impossible-to-reach code block. So the compiler is free to (i.e. _may_) not generate any processor instructions for the unproductive source code statements. But the compiler isn't required to save code space by throwing away the block.
So you really should use the preprocessor fully (setting the symbol that selects include/skip, and that checks this symbol) to reduce the code size. Only then will you have a valid contract guaranteeing removal of the unwanted code.
If you do not use the preprocessor, but still see the code size shrink, that will be caused by the _may_ rule. The compiler _may_ be smart enough, and the code _may_ be simple enough, that the compiler can deduce that it can throw away code. Some compilers are marvels at analyzing code. Some are rather stupid. But the marvel and the stupid compiler will honor the intentions of the #if constructs.
That makes sense. Sounds like, whether my code needs it or not using the optimization I'm using, it's in my best interest to add the #if statements to ensure I'm not relying on "MAY" conditions to occur.
At least now I understand what's happening and why. Thanks, guys!