Short story: I want to enforce a run-time condition check in certain conditionally-compiled code blocks, but not others.
Long story:
Our C code base relies heavily on profiling.
We have lots of different profiles, and almost each module has #ifdefs for at least 5-6 different profiles, wrapping large segments of code.
We have added a new requirement - for certain profiles (Let's say <A> and <B>), the conditionally-compiled code will only be run if a specific condition is met. For the other profiles (Let's say <C>) this is not required.
i.e., this is how the code looks now:
#ifdef <A>
/* Profiled code… */
#endif /* <A> */
#ifdef <B>
/* Profiled code… */
#endif /* <B> */
#ifdef <C>
/* Profiled code… */
#endif /* <C> */
This is how we need it to look:
#ifdef <A>
if (new_condition)
{
/* Profiled code… */
}
#endif /* <A> */
#ifdef <B>
if (new_condition)
{
/* Profiled code… */
}
#endif /* <B> */
#ifdef <C>
/* Profiled code… */
#endif /* <C> */
So far, so good.
However, with the above implementation the new requirement isn't really maintainable.
It doesn't stop anyone not familiar with the requirement to add a new profiled code block, without adding the check for new_condition.
So I want to force our engineers to check for this condition whenever adding new blocks that are profiled under <A> and <B>, but not for code profiled under <C>.
Theoretically, the best solution would probably be a way to fail the build process, if there exists an #ifdef <A> or #ifdef <B> that isn't directly followed by if (new_condition).
Thing is, I have no idea to do that. Do any of you have?
I'm reasonably sure it can't be done as described. It would seem that your engineers get to write all the code from the #ifdef to the #endif and the only 'hooks' you have are the conditional symbols and condition. That isn't enough. Some semi-random thoughts:
You could turn the 'condition' into a function call and count how often it gets called.
You could demand certain 'null behaviour' when all the conditions are set to false.
You could create some function your engineers have to call inside their block to get access to something, and check at runtime that it doesn't get called if the condition is false.
Ultimately I think you'd be better to use source code analysis tools to analyse the source code and report on coding style breaches. That would be CppCheck or one of these: http://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis.
Bit hard to answer this, since everything is so fuzzy :) But I would suggest to use somekind of wrapper, which the person editing the code isn't allowed to change:
typedef void(*stuff_ptr)(void);
inline void do_stuff (stuff_ptr stuff)
{
#if defined(A) || defined(B)
if (!new_condition)
{
return ;
}
#endif
stuff();
}
#ifdef A
do_stuff(A_stuff);
#endif
#ifdef B
do_stuff(B_stuff);
#endif
#ifdef C
do_stuff(C_stuff);
#endif
This will not fail to build, but instead prevents incorrect builds from happening in the first place.
do_stuff() can be implemented as a function-like macro if needed, but avoid that if you can. The "new_condition" could be passed as another parameter, if needed.
One idea that maintains your current begin macro, end macro style blocks might be something like the following:
#include <stdio.h>
#define FOO 1
#define BAZ 1
int condition_a = 1;
int condition_b = 0;
#ifdef FOO
# define FOO_BEGIN if (condition_a) {
# define FOO_END }
#else
# define FOO_BEGIN if (0) {
# define FOO_END }
#endif
#ifdef BAR
# define BAR_BEGIN if (condition_b) {
# define BAR_END }
#else
# define BAR_BEGIN if (0) {
# define BAR_END }
#endif
#ifdef BAZ
# define BAZ_BEGIN if (1) {
# define BAZ_END }
#else
# define BAZ_BEGIN if (0) {
# define BAZ_END }
#endif
int main (int argc, char ** argv)
{
FOO_BEGIN
printf("in foo\n");
FOO_END
BAR_BEGIN
printf("in bar\n");
BAR_END
BAZ_BEGIN
printf("in baz\n");
BAZ_END
}
prints
in foo
in baz
You're going to have to either update the macros that define entering and exiting blocks or require something inside of those ifdefs.
Related
Why the code inside the #ifdef INITIALISATION and #endif is not executed?
int main(void)
{
uint8_t DLEVEL = 10;
#if DLEVEL > 5
#define INITIALISATION
#endif
while (1)
{
#ifdef INITIALISATION
Display(); // This line is never being executing :: please help for a solution
#endif
}
}
edited...
Thanks for the reply
Actually the below mentioned logic of the code is used as a part of my code memory optimization.
Now the code memory size is overflowed, so i need to execute the one time initializations when the SYM_DLEVEL value is 10 and then the value of SYM_DLEVEL is changed from 10 to 2, then the initial sections i need to be automatically commented or disabled and then only the Display_2() function needed to be enable and need to execute.
Is it possible?
#define SYM_DLEVEL 10
int main(void)
{
#if SYM_DLEVEL > 5
Display_1(); // need to execute this line once(before the value changes from 10 t0 2)
#endif
#define SYM_DLEVEL 2 // after this line execution i need to automatically disable the above section and automatically enable the below section
#if SYM_DLEVEL < 5
#define INITIALISATION // need to execute only when value changes from 10 to 2
#endif
while (1)
{
#ifdef INITIALISATION
Display_2();
#endif
}
}
It doesn't execute code because the preprocessor runs in the compiler, while the local variable DLEVEL is assigned during execution.
The preprocessor simply looks for a preprocessor symbol DLEVEL that evidently is undefined.
Undefined symbols are equated to 0, so the symbol INITIALISATION isn't defined.
To make it work define a preprocessor symbol, i.e. SYM_DLEVEL, to be used in the conditional preprocessing, and eventually assign it to the runtime variable. I.e.
#define SYM_DLEVEL 10
int main(void)
{
uint8_t DLEVEL = SYM_DLEVEL;
#if SYM_DLEVEL > 5
#define INITIALISATION
#endif
while (1)
{
#ifdef INITIALISATION
Display(); // This line is now is executed
#endif
}
}
Remember that preprocessing is more or less a text processor (which actuates on base piece of text, tokens, as outlined in comments below), and is executed before the compilation of the code. It doesn't know about runtime variables and their assignments, it only knows symbols defined with a preprocessor directive (#define).
Don't confuse actions as dead code removal or other optimization made by compiler with what the preprocessor can do. The golden rule is: "preprocessing only understand preprocessing objects, C code is a plain text without any special meaning for it".
I'm writing a C program that uses a custom logging function to debug my program. Whenever I compile my program as a release version, I want all of my logging functions to be stripped from the code so it won't show up if someone tries to disassemble it.
Take the following example:
#include <stdio.h>
void custom_logging_function(char* message)
{
// Do something here
}
int main()
{
custom_logging_function("Hello world"); // This call should be removed.
return 0;
}
How could I make it so that the custom_logging_function and it's arguments aren't compiled into my program without having to write include guards everywhere throughout my code? Thank you
You can use pre-processor flags, for example:
#include <stdio.h>
#ifdef DEBUG
void custom_logging_function(char* message)
{
// Do something here
}
#else
#define custom_logging_function(x) ((void) 0)
#endif
int main()
{
custom_logging_function("Hello world"); // This call should be removed.
return 0;
}
With this code you will have to tell the "debug" target to define DEBUG, if you want to define something specifically for the "release" target you can replace #ifdef DEBUG with #ifndef NDEBUG and add the NDEBUG flag to the "release" definitions.
Edit:
Changed #define custom_logging_function(x) 0 to #define custom_logging_function(x) ((void) 0) inspired by #JoachimPileborg his answer.
Assuming you only want the logging calls to happen in a debug-build of your application, and not the release build you send to customers, you can still use the preprocessor and conditional compilation for it. It can be made vert simple though by using macros instead of having checks at every call.
Something like this in a heder file:
#ifdef _DEBUG
void custom_logging_function(char* message);
#else
# define custom_logging_function(message) ((void) 0)
#endif
You could use an empty macro body for the release-macro, but that can cause some compilers to give "empty statement" warnings. Instead I use an expression casted to void (to tell the compiler that the result of the expression will not be used). Any smart compiler will not include the expression after optimization.
Is it possible to put a #endif inside a #if as the block's 'content' not as the pair #endif for the #if?
#if (SOME_CONDITION)
#if (ANOTHER_CONDITION)
#endif // pair endif for #if (SOME_CONDITION)
#if (SOME_CONDITION)
#endif // pair endif for #if (ANOTHER_CONDITION)
#endif // pair endif for #if (SOME_CONDITION)
If this is not possible how to conditionally compile a #if ... #endif pair?
This is what I was doing.
I was modifying a code base that we bought from another company. To compile it with and without my modifications easily I was using a macro say like shown below.
#if (MY_COMPANY_EDITS_ENABLED)
// My Modified code goes here
#else
// unmodified code from another company
#endif
In this way I could easily compile in/out my modifications while maintaining readability about my edits. I was using the same #if #else #endif blocks everywhere. But then I came across a code that is being compiled in, in the original unmodified code base, based on some macro value.
#if (FEATURE_A_IS_ENABLED)
// Line 1
// Line 2
#endif
But I want to compile this code [Line 1 and Line 2] regardless of the macro value FEATURE_A_IS_ENABLED
My first thought was to follow the same convention that I used till now [to maintain readability about my edits].
#if (MY_COMPANY_EDITS_ENABLED)
//#if (FEATURE_A_IS_ENABLED)
#else
#if (FEATURE_A_IS_ENABLED)
#endif
// Line 1
// Line 2
#if (MY_COMPANY_EDITS_ENABLED)
// #endif
#else
#endif
#endif
Then I realized this is not possible.
I know, alternative methods exist to achieve the same. But was wondering whether I could use the same convention
#if (MY_COMPANY_EDITS_ENABLED)
// My Modified code goes here
#else
// unmodified code from another company
#endif
in this case too.
No, it's not possible. The first #endif will be matched with the most recent #if or #else, so your code will be interpreted like this:
#if (SOME_CONDITION)
#if (ANOTHER_CONDITION)
#endif // pair endif for #if (ANOTHER_CONDITION)
#if (SOME_CONDITION)
#endif // pair endif for the second #if (SOME_CONDITION)
#endif // pair endif for the first #if (SOME_CONDITION)
This is not possible, as the preprocessor only does a single pass over your file, and the #endif gets matched with the preceding #if. If you want to make an #if/#endif block conditional, then just nest it inside another #if/#endif block:
#if CONDITION_A
# if CONDITION_B
...
# endif /* CONDITION_B */
#endif /* CONDITION_A */
Put another way, it's not possible to have preprocessing directives construct other preprocessing directives, as the output from the initial "construction" phase will not be reparsed by the preprocessor.
The (silly) example below wouldn't work either for example, even assuming the newlines wouldn't be an issue (which they would be here):
#if DEFINE_X_TO_FIVE
#define X
#endif
#if DEFINE_X_TO_FIVE
5
#endif
I recommend making the changes based on feature sets rather than whether or not they are yours or not then group them together to make a given version (MY_COMPANY_EDITS_ENABLED) or whatever:
#if (MY_COMPANY_EDITS_ENABLED)
#define FEATUREA
#define FEATUREB
#define FEATUREC
#define FEATURED
#else
#define FEATUREA
#undef FEATUREB
#undef FEATUREC
#undef FEATURED
#endif
#ifdef FEATUREA
//do some feature A stuff
#endif
// do code
#ifdef FEATUREB
//do some feature B stuff
#endif
#ifndef FEATUREC
//do some stuff if not feature C
#endif
// etc...
This is a lot more flexible in the long run and lets you switch changes features on and off with a rebuild.
Off course you can nest your preprocessor directives:
#ifdef CONDITION1
// some code here
# ifdef CONDITION2
// some else here
# endif
#endif
But make sure to end each condition properly.
See also: http://www.ioccc.org/years.html#1995_vanschnitz and http://www.ioccc.org/years.html#2004_vik2
I've got a list of definitions: MASTER, SLAVE0, SLAVE1, ... SLAVE9 to control which array of audio data is programmed into a microcontroller. The micro can hold no more than one sound file, so I have included the following definitions at the top of my main.c file:
#define MASTER
#define SLAVE0
#define SLAVE1
....
#define SLAVE9
Then, I write the following in my audio array:
#if defined(MASTER)
uint8_t sound[4096] PROGMEM = {127,126, ... }
#elif defined(SLAVE0)
uint8_t sound[4096] PROGMEM = {126,128, ... }
....
#else
#ERROR "One of MASTER-SLAVE9 must be defined!"
#endif
The person wishing to compile must then go through and comment out one and only one of the #define lines. This is not only tedious, but also error-prone. So, I'm looking to simplify the process. Any pointers for any of the following tasks would be helpful:
How can I test a list of macros for the presence of one and only one of these options? A simple if defined(MASTER) && !(defined(SLAVE0) || defined(SLAVE1) ...) would require 11 such tests, each with 11 subtly different conditions. It's a one time expense, but it's kinda ugly. It feels like this might be a common need, and that there ought to be a better way.
How can I simplify the compilation process? I've been using AVRStudio with WinAVR t0 compile. It has an 'export makefile' option, but I have no experience with it. I'm stuck doing this on Windows. An ideal process would build all 11 configurations in a single command, and then I could go through and program each one to the microcontroller individually. The current, very much less-than-ideal build process involves editing the source each time I want to build, and renaming/moving the output file.
You can use a single test to ensure that only one of the macros is defined.
#if (defined(MASTER) + defined(SLAVE1) + defined(SLAVE2)) != 1
#error "Too many macros defined"
#endif
As for the definition itself, most compilers allow you to define a macro using a command line option; this might be cleaner than a file with a "configurable options list." You would then be able to create multiple build configurations, each of which defines a different macro, and build them each in sequence (I'm not familiar with your build system to be able to explain how exactly you need to do that).
I would just make a block comment with the name of all possible constants, and follow it with a single define. Who wants to compile just writes what he wants. First time he will check the comment to see the list, then he will just write.
Or even better, keep this list in a comment (for reference) and use the -D option that most compilers have (-DMASTER to define master for example) and if your tool supports it, make a build configuration for each where you change the -D value. Using a different build configuration i guess you could also change the output file name, so that would kill two birds with a stone.
Why not something like:
#define ARRAY_NAME (SLAVE0)
...
#if (ARRAY_NAME == MASTER)
// blah
#elif (ARRAY_NAME == SLAVE0)
// blah
// etc.
or even better, just:
#define ARRAY_MASTER { 1, 2, 3, 4 }
#define ARRAY_SLAVE0 { 5, 6, 7, 8 }
// etc.
...
const uint8_t sound[] = ARRAY_MASTER;
You are need an error message when you deined mre than one macro? Well, just write:
#ifdef MASTER
uint8_t sound = { ... };
#endif
#ifdef SLAVE0
uint8_t sound = { ... };
#endif
#ifdef SLAVE1
uint8_t sound = { ... };
#endif
And compiler will complain that one identifier defined multiple times.
Also why not use this?
#define SLAVE <n>
uint8_t sound_master = { ... };
uint8_t sound_slave_0 = { ... };
uint8_t sound_slave_1 = { ... };
uint8_t sound_slave_2 = { ... };
#define XCAT(a,b) a##b
#define CAT(a,b) XCAT(a,b)
#ifdef SLAVE
#define sound CAT(sound_slave_,SLAVE)
#endif
#ifdef MASTER
#ifdef sound
/* warnin or so. but if you need an error just remove this ifdef **/
#endif
#define sound sound_master
#endif
In C/C++
What happens to code placed between an #if 0/#endif block?
#if 0
//Code goes here
#endif
Does the code simply get skipped and therefore does not get executed?
Not only does it not get executed, it doesn't even get compiled.
#if is a preprocessor command, which gets evaluated before the actual compilation step. The code inside that block doesn't appear in the compiled binary.
It's often used for temporarily removing segments of code with the intention of turning them back on later.
It's identical to commenting out the block, except with one important difference: Nesting is not a problem. Consider this code:
foo();
bar(x, y); /* x must not be NULL */
baz();
If I want to comment it out, I might try:
/*
foo();
bar(x, y); /* x must not be NULL */
baz();
*/
Bzzt. Syntax error! Why? Because block comments do not nest, and so (as you can see from SO's syntax highlighting) the */ after the word "NULL" terminates the comment, making the baz call not commented out, and the */ after baz a syntax error. On the other hand:
#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif
Works to comment out the entire thing. And the #if 0s will nest with each other, like so:
#if 0
pre_foo();
#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif
quux();
#endif
Although of course this can get a bit confusing and become a maintenance headache if not commented properly.
It permanently comments out that code so the compiler will never compile it.
The coder can later change the #ifdef to have that code compile in the program if he wants to.
It's exactly like the code doesn't exist.
I'd like to add on for the #else case:
#if 0
/* Code here will NOT be complied. */
#else
/* Code will be compiled. */
#endif
#if 1
/* Code will be complied. */
#else
/* Code will NOT be compiled. */
#endif
When the preprocessor sees #if it checks whether the next token has a non-zero value. If it does, it keeps the code around for the compiler. If it doesn't, it gets rid of that code so the compiler never sees it.
If someone says #if 0 they are effectively commenting out the code so it will never be compiled. You can think of this the same as if they had put /* ... */ around it. It's not quite the same, but it has the same effect.
If you want to understand what happened in detail, you can often look. Many compilers will allow you to see the files after the preprocessor has run. For example, on Visual C++ the switch /P command will execute the preprocessor and put the results in a .i file.
Lines beginning with a # are preprocessor directives. #if 0 [...] #endif blocks do not make it to the compiler and will generate no machine code.
You can demonstrate what happens with the preprocessor with a source file ifdef.cxx:
#if 0
This code will not be compiled
#else
int i = 0;
#endif
Running gcc -E ifdef.cxx will show you what gets compiled.
You may choose to use this mechanism to prevent a block of code being compiled during the development cycle, but you would probably not want to check it in to your source control as it just adds cruft to your code and reduces readability. If it's a historical piece of code that has been commented out, then it should be removed: source control contains the history, right?
Also, the answer may be the same for both C and C++ but there is no language called C/C++ and it's not a good habit to refer to such a language.
Not quite
int main(void)
{
#if 0
the apostrophe ' causes a warning
#endif
return 0;
}
It shows "t.c:4:19: warning: missing terminating ' character"
with gcc 4.2.4
It is a cheap way to comment out, but I suspect that it could have debugging potential. For example, let's suppose you have a build that output values to a file. You might not want that in a final version so you can use the #if 0... #endif.
Also, I suspect a better way of doing it for debug purpose would be to do:
#ifdef DEBUG
// output to file
#endif
You can do something like that and it might make more sense and all you have to do is define DEBUG to see the results.