I am refactoring a few c code files based on a variable set in Makefile, and I realize that there are lots of code that need conditional compilation across the files. I find that I'm doing this a lot:
#if COND1
void func1(int a1, int b1) {
Struct1 info;
#else
void func1(int a1) {
Struct2 info;
#endif
switch (info.type)
{
#if COND1
case c1:
case c2:
...
#else
case c3:
#endif
case c4:
...
}
The code soon becomes messy and ugly in my opinion.
But the portion of the code that needs conditional compilation is like 10%-20% and all the others are exactly the same, so I don't think I need extra files just to distinguish between the two versions of the code.Is there any way I can do this more elegantly? Inserting #if... everywhere in the code makes it a headache just to read. I'm quite new to C so please let me know if there's anything I need to catch up on and any advice is appreciated, thanks.
To avoid many conditional compilation directives, you could use this approach with macros:
#if COND1
#define Func1Struct Struct1
#else
#define Func1Struct Struct2
#define func1(a, b) (func1)(a)
#endif
void func1(int a1, int b1) {
Func1Struct info;
...
The advantage of defining func1 as a macro is you only have a single definition point for the function, which is better for ctags and debugging and the call sites are handled transparently too.
Platform specific case values still require explicit preprocessor directives.
This is not elegant by any means, but it does hide some of the ugliness effectively.
Related
Consider the following simple C/C++ example:
#define FOO
...
#ifdef FOO
bar++;
#endif
OK, now I would like to fit that (and any other similar) conditional into one line for the code readability sake (the code has tens of single-line statements that all need to be conditional each depending on different define). Something that, when used, would look like:
#define FOO
...
MY_IFDEF(FOO,bar++;) //Single-line conditional
The goal is to have a reusable macro that can take an arbitrary identifier and, compile the statement if such identifier has been #define-d previously, and do it all in a single line.
Any ideas?
UPDATE0: the code must compile for both C and C++
You can't use #ifdef while expanding macros, but you can totally precheck it and declare empty statement if condition is not met.
#ifdef FOO
#define MY_IFDEF(x,y) some-processing-you-need
#else
#define MY_IFDEF(x,y) ;
#endif
Also check out new feature of C++: constexpr this can also be usable.
UPDATE4: As pointed out by #Alex Bakanov you can't use #ifdef while expanding macros, so there is no single line solution for your question which works in all cases. Nevertheless, I hope the idea I wrote here may be useful.
if you use #define FOO 1 or #define FOO 0, combination of #define and if constexpr can be used. Note that it gives an error if FOO is not defined. This program gives 1 as result:
#include<iostream>
#define FOO 1
#define MY_IFDEF(x,y) if constexpr (x) y;
int main()
{
int bar =0;
MY_IFDEF(FOO,bar++)
std::cout << bar << "\n";
}
UPDATE: Based on #eerorika's comment to avoid the error if FOO is not defined, the following declaration has to be added:
constexpr bool FOO = false;
UPDATE2: This version works in any circumstances, the only question is that is it worth the effort?
#ifdef FOO
constexpr bool USED_FOO = true;
#else
constexpr bool USED_FOO = false;
#endif
#define MY_IFDEF(x,y) if constexpr (USED_##x) y ;
UPDATE3: C compatible version. Note that in this case in theory it is evaluated runtime not compile time, but the compiler will realize that it is always true/false and generates the code accordingly:
#ifdef FOO
const static bool USED_FOO = true;
#else
const static bool USED_FOO = false;
#endif
#define MY_IFDEF(x,y) if (USED_##x) y;
I have a function dangerous(GEN x) which is called frequently in my code, where GEN is a typedef. For debugging purposes, I would like to add checkSafe to all instances of this function, something like
#ifdef DEBUG
#define dangerous(x) GEN __x = (x); if(checkSafe(__x)) dangerous(__x)
#endif
but I'm concerned that this might not work as intended. What's the right way to do something like this? The function is used too often to instrument each use individually and it is not desirable to check outside debug mode (for various reasons).
Things to be aware of / careful about:
Using a macro and a function with the same name at the same time. While it can produce valid C, you'll have to 1) take extra precautions to avoid unwanted expansion (either always define the function before the macro, or enclose the function name in parentheses at definition time) and 2) double check that every use of the function also includes your instrumenting code.
Solution: rename the original function into something like _dangerous.
Using the macro in various situations:
in an if with a single statement: if (foo) dangerous(x);
around an else from the parent if: if (foo) dangerous(x); else bar();
when leaking variables into the parent namespace can break things: GEN __x = 5; dangerous(__x);.
Solution: enclose the macro in a construct like do { ... } while(0).
You must take into account any side effects at copy time, like resource allocation or CPU intensive operations (since GEN is a typedef, this is likely not a concern).
Lastly, you may also want to complain when checkSafe fails, e.g. by logging an error message, or even aborting the program.
Putting the above together, you would instrument the function like this:
#ifdef DEBUG
#define dangerous(x) do { \
GEN __x = (x); \
if (checkSafe(__x)) \
_dangerous(__x); \
else \
complainAbout(__x); \
} while(0)
#else
#define dangerous _dangerous
#endif
If dangerous() returns a value (e.g. int) that you want to use.
Solution: Define a function to instrument your original function and pass the return value up:
#ifdef DEBUG
static inline int dangerous(GEN x) {
if (checkSafe(x))
return _dangerous(x);
complainAbout(x);
return ERROR_CODE;
}
#else
#define dangerous _dangerous
#endif
I need to temporarily overwrite a macro and then restore it. Like:
#define FOO X
#save FOO
#define FOO Y
...
#restore FOO
Is it possible in standard C preprocessor? In GCC?
ADDED. About real world example. I use a global macro for error exception. It acts like assert, but for persistent usage, not only for debug versions; so, for example, I usually call functions (with side-effect) inside the macro. It's defined once, but the definition isn't persistent; therefore I don't know it a-priori. For some piece of code I need its own, modified version of the macro, but I want to save general style of code. It's looks ugly when one part of code uses the one macro, other part uses other macro -- both macros have the same purpose, but slightly different implementation.
So, it's good for me to save original macro temporarily, use different version for a part of code, after that restore original macro.
This is possible with #pragma push_macro and #pragma pop_macro. These are not standard C—they're originally an MSVC extension—but clang supports them, and so does GCC.
Example usage:
int main() {
#define SOME_MACRO 1
printf("SOME_MACRO = %d\n", SOME_MACRO);
#pragma push_macro("SOME_MACRO")
#define SOME_MACRO 2
printf("SOME_MACRO = %d\n", SOME_MACRO);
#pragma pop_macro("SOME_MACRO")
printf("SOME_MACRO = %d\n", SOME_MACRO);
return 0;
}
prints:
SOME_MACRO = 1
SOME_MACRO = 2
SOME_MACRO = 1
You can also #undef a macro inside a push_macro / pop_macro pair, and the pop_macro call will redefine it.
As already said, it is not really possible. Depending on the situation, this might be a workaround:
#include "generalmacrodefs.h" // put them in here or include them indirectly
#undef macro1
#define macro1 "specialized temporary value"
#undef macro1
#include "generalmacrodefs.h" // restores
This requires that generalmacrodefs.h uses a pattern like this at least for the definitions you might temporarily overwrite:
#ifndef macro1
#define macro1 "original value"
#endif
The closest you can come in C is the #undef directive, which simply undefines the macro, allowing it to be replaced:
#define FOO X
...
#undef FOO
#define FOO Y
...
#undef FOO
#define FOO X
The problem is that you cannot know the 'old' value of FOO once you redefine it - so your values must be hard-coded in one place.
You cannot create a macro to save the values for you either, as it isn't possible to have a macro that creates other preprocessor directives in standard C.
I'm wondering why I have never seen the following way to implement templates
in C before. My idea was to make the Preprocessor to the templating-work.
container.h:
#ifndef TEMPLATE_TYPE
#error "missing decalaration TEMPLATE_TYPE"
#endif
#define _CONCAT(a, b) a##b
#define _EVALUATOR(a, b) _CONCAT(a, b)
#define MAKE_NAME(a, b) _EVALUATOR(a, b)
typedef struct {
TEMPLATE_TYPE data;
} MAKE_NAME(Container_, TEMPLATE_TYPE);
main.c:
#define TEMPLATE_TYPE int
#include "container.h"
int main() {
Container_int c;
c.data = 99923;
}
So, what's the case?
This is just considered "bad style"
It's so obvious that nobody would write an article about it
There are a lot of articles, just google man!
I would appreciate comments about this technique when you are not planning
to answer with #3.
You can do incredible things (good and evil) with the preprocessor. Whether it's considered bad style or not is a judgement call, and it largely depends on the quality, readability, and maintainability of the code that results. Complicated preprocessor macros are a pain to write, debug, and maintain. However, the best C code is the code you don't write, and macros are great for automatically generating variations on a theme.
Here are some good examples of preprocessor (ab)use:
The SimpleScalar processor simulator's machine.def file (which is C code, despite the extension)
The canonical queue.h linked-list headers
The SimpleScalar code uses a pattern like your suggestion, above, where the #include is preceded by a #define that gives the header some direction.
If you're considering serious use of the preprocessor, you should look at the Boost preprocessor library. (Don't be put off by Boost's C++ roots, the preprocessor macros work fine with C.)
Instead of
typedef struct {
TEMPLATE_TYPE data;
} MAKE_NAME(Container_, TEMPLATE_TYPE)
you might want to do
#define MAKE_CONTAINER(type) typedef struct MAKE_NAME(Container_, type) { type data; } MAKE_NAME(Container_, type)
in order to be able to do
#include "container.h"
MAKE_CONTAINER(int);
MAKE_CONTAINER(double);
int main() {
Container_int c; // one way to go
struct Container_double d; // my preferred way: don't typedef when not needed; let the structs be obvious.
c.data = 99923;
d.data = 3.5;
}
I have a performance sensitive CUDA code, which I'm using
#ifdef DEBUG_<NAME_OF_SECTION>
...
#else
...
#endif
...conditionals to encapsulate speed-crippling debugging code, which grabs extra info off the GPU.
Everything goes well in emacs (Centos 6.0) up until the #else.
This deindents (by 1 tab) the text inside the else clause of the preprocessor conditional and continues to deindent everything afterwards.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note:
) replication inside preprocessor conditionals seems to be properly handled by the C-mode. But ); duplication breaks things, forcing you to move the ); outside the conditional ... oh dear how inconsistent. I'm keeping this question open until we get proper elisp code to fix this inconsistency.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NOTE on current answer:
Jens has provided inaccurate information in claiming that indenting nested ) inside conditionals is "impossible". It is not only possible, but Emacs' C-Mode actively does this. Note the proper indentation of the example c program at the end of this question post for proof of that. So it would stand to reason that ); is also feasible to indent, though caution should be exercised for the reasons outlined by Jens.
Anyhow, I want to make sure people see that statement is incorrect, so they do not think this question is unanswerable. I will remove this comment and my downvote on Jens' post when he amends his inaccurate statements to reflect that it is possible, is implemented in C-mode for the very case of ) he outlines, but is not recommended.
Currently I'm resorting to manually respacing things forward one tab, but it's wasting a lot of time (the code is long).
Any idea what I can add to my ~/.emacs file to fix this???
Thanks in advance!
EDIT 1
I should mention that the clause it seems to be choking on is a function closing, e.g.
MyFunc<<<Blk,Thr>>>(Stuff1,
#ifdef DEBUG_FUNC1
Stuff2,
dev_Debug);
#else
Stuff2); //Deindents here.
#endif
//Everything here on out is deindented.
It may be a specific failure on that kind of code structure...
EDIT 2
Here's a simply C code version... the code works as expected, but not the deindent on the last #else clause...
#include <stdio.h>
//#define DEBUG
void printer
(int A,
#ifdef DEBUG
int B,
int C)
#else
int B)
#endif
{
#ifdef DEBUG
printf("A: %i, B: %i, C: %i\n", A, B, C);
#else
printf("A: %i, B: %i\n", A, B);
#endif
}
int main()
{
int A = -3;
int B = 1;
int C = 3;
printer(A,
#ifdef DEBUG
B,
C);
#else
B);
#endif
return 0;
}
...that's along the lines of what I'm doing. I know it works syntactically in C (or at least I think does... it gives correct results), however emacs doesn't like that #else clause inside the function call....
I think the problem is in the logic of your code. Logically you have different parameters in a function parameter list. The closing parenthesis should not be part of the conditional.
MyFunc<<<Blk,Thr>>>(
Stuff1,
#ifdef DEBUG_FUNC1
Stuff2,
dev_Debug
#else
Stuff2
#endif
);
Or alternatively you should have two complete versions of the prototype that are chosen according to your debug macro. Everthing else is not only difficult to parse for emacs (or probably any other editor) but also for the poor human that comes after you.
What you want is not possible since the indentation level of a code might depend on the macros:
#if A
(
#endif
something
#if B
)
#endif
where A and B are the same for all valid compilations. Emacs can't know without assuming values for A and B, how to indent.