Redefining macros with old contents / Making a file include counter - c

I want to count the amount of includes of one specific file.
My first idea was to define a macro holding the count and redefining it when a specific file is included. I have to find a way that the macro is expanded, to be used in a new definition with the same name again, else its old value would simply be destroyed by undef. Is there a way to expand the macros when the macro is defined. Or is there an other way to count including files?
FILE main.c:
#define INCLUDE_COUNT 0
// some other files include the file include_counter.h here
You would think that the compiler could replace INCLUDE_COUNT by 0 or one of its redefinitions in the first line, but it doesn't because macros inside macro-definitions are expanded when the macro is used in non-macro code.
FILE include_counter.h:
#define OLD_INCLUDE_COUNT (INCLUDE_COUNT)
#undef INCLUDE_COUNT
#define INCLUDE_COUNT (OLD_INCLUDE_COUNT + 1)
// INCLUDE_COUNT would be expanded to ((INCLUDE_COUNT) + 1)

Is there a way to expand the macros when the macro is defined.
Yes. But beware... using this as a means of generating unique symbols may cause unexpected linker issues if your symbols have external linkage.
Overview
The key problem here is that macros are not variables. With variables, if I have x=3*3; y=x;, then I'm assigning the value of x to y. With macros, if I have #define PPX 3*3 #define PPY PPX, then I'm literally assigning PPX to PPY. If I then evaluate PPY, it expands to PPX, and then to 3*3 but only because PPX is currently defined as 3*3.
However, there is a way around this. The preprocessor can evaluate expressions; it just uses conditional directives to do so. But due to the fact that this can branch, we can define macros conditionally based on PPX's value (as opposed to its replacement list). For example:
#if (PPX)%10==9
# define PPX_DIGIT_0 9
#elif (PPX)%10==8
# define PPX_DIGIT_0 8
...
So whereas PPY critically relies on PPX being defined as 3*3 to expand to 3*3; since PPX_DIGIT_0 is literally defined as 9, PPX can be undefined, and PPX_DIGIT_0 will still expand to 9. Note also that the conditional played a role in reducing the expression; (3*3)%10 is just equal to 9, causing the 9 branch to be hit. That loses the expression per se, picking up just the evaluation... which we want.
That's the idea. In practice, this requires a fair amount of code; fortunately, boost's preprocessor library already has it done for you, so here are two approaches using boost:
Approach 1: Using Boost Slots
include_counter.h:
#include <boost/preprocessor/slot/slot.hpp>
#if !(INCLUDE_COUNT)
# define INCLUDE_COUNT 0
# define BOOST_PP_VALUE INCLUDE_COUNT
# include BOOST_PP_ASSIGN_SLOT(1)
# undef BOOST_PP_VALUE
# undef INCLUDE_COUNT
# define INCLUDE_COUNT BOOST_PP_SLOT(1)
#endif
#define BOOST_PP_VALUE 1+INCLUDE_COUNT
#include BOOST_PP_ASSIGN_SLOT(1)
Boost slots evaluate macros and store their results using special internal states. You get 5 slots (code above is using slot 1), so you can store 5 numbers. This solution just initializes the slot to 0 before incrementing on the first include, then essentially just increments.
Approach 2: Use Boost Counter
include_counter.h:
#if !(INCLUDE_COUNT)
# include <boost/preprocessor/slot/counter.hpp>
# define INCLUDE_COUNT BOOST_PP_COUNTER
#endif
#include BOOST_PP_UPDATE_COUNTER()
Same idea, though it "consumes" boost counter.
Both boost solutions take the approach I just described. There's also a boost increment macro; feel free to ignore that, since (a) you're evaluating anyway, and (b) boost increment is a bit whimpy (with its maximum limit of 256).
You can also roll your own solution. But when you're done, it's going to look similar to boost's solution anyway. (The advantage is, your new "slot" will be independent of boost counter and boost slots).

An alternative is not to use the macros but the compiler. Many compilers have a "show includes" flag. For instance, in gcc, it is -H. For visual studio, it is /showincludes. Just pipe the compiler output to a file and count the number of lines.
# linux
gcc -H ... fred.c 1> incs.txt 2>&1
wc -l incs.txt
rem Windows
cl /showincludes ... fred.c 1> incs.txt 2>&1
find /v /c "" < incs.txt
# powershell
cl /showincludes ... fred.c 1> incs.txt 2>&1
get-content incs.txt | measure-object -l
Note that this will count the same file if it has been included multiple times, even though it does not get processed because of the guards.

Related

How to define a C macro that uses another macro?

I have the following scenario...
Header file:
#define TRIG_INDEX 200
#define PATH(target_p) some.path.to.target##target_p
Source file:
read_from_target(PATH(TRIG_INDEX));
As the PATH macro appends the target_p to the text at the end, compilation fails as
some.path.to.targetTRIG_INDEX is not a valid path.
I was expecting to get read_from_target(some.path.to.target200) in the above scenario.
How can I (if at all) define the macros to accept such scenario?
The argument must be expanded by the macro:
#define TRIG_INDEX 200
#define PATH_TARGET(x) some.path.to.target##x
#define PATH(target_p) PATH_TARGET(target_p)
The pre-processor macro expansion/replacement rules for function-like macros are rather intricate. Basically it does so in the following order:
The stuff after the macro name is known as the replacement list. In this case PATH_TARGET(target_p) - things that PATH should be replaced with.
The occurrence of ## or # together with a macro parameter means that the parameter gets replaced with its corresponding pre-processor token sequence (if applicable). In this case, the parameter target_p gets replaced with TRIG_INDEX, so we get some.path.to.target##TRIG_INDEX creating the new pre-processor token some.path.to.targetTRIG_INDEX , which is not as intended.
Other macro parameters get expanded. Doesn't apply here.
The replacement list is then rescanned for macro names to expand, but it's too late since pre-processor token concatenation with ## has already occurred.
The part "other macro parameters get expanded" above is useful to fix the problem. So macro parameters in the replacement list take precedence over macro names. We can take advantage of this by adding a helper macro:
#define TRIG_INDEX 200
#define EXPAND(tgt) some.path.to.target##tgt
#define PATH(target_p) EXPAND(target_p)
Now in the expansion of the replacement list of PATH, we first get macro parameter expansion: taget_p is replaced and we get EXPAND(TRIG_INDEX). The replacement list is then rescanned for macro names to replace, the pre-processor finds two such macro names: EXPAND and TRIG_INDEX. Both are expanded and so TRIG_INDEX is replaced with 200. Then EXPAND is expanded recursively according to the same rules (## enforcing an expansion of that macro parameter tgt into 200 before anything else).
For details, see the C17 standard chapter 6.10.3 - this chapter is also the one which specifies the behavior of the # and ## operators.

Documenting conditional exclusive code in Doxygen

Consider
// EXTERNAL_MACRO is an external macro defined to some value by build system
#if EXTERNAL_MACRO == 1
# define EXCLUSIVE_MACRO_ONE
#elif EXTERNAL_MACRO == 2
# define EXCLUSIVE_MACRO_TWO
#else
# define EXCLUSIVE_MACRO_OTHER
#endif
At built time, only one of the EXCLUSIVE_MACRO_... macros is defined.
How can one document all three EXCLUSIVE_MACRO_... macros in Doxygen?
PREDEFINED configuration setting is not helpful for this because it allows to define EXTERNAL_MACRO to only a single value (and therefore document only a single EXCLUSIVE_MACRO_...).
This SO answer offers a work-around solution that does the job but it requires an additional logic. I am looking for a simpler answer, one that uses Doxygen configuration (if possible) rather than modifying the original code (though some modification is of course fine).
See related question and answer:
Document a config macro with doxygen
Basically:
In the doxygen configuration file, add:
PREDEFINED = IN_DOXYGEN
Somewhere in the source code, add:
/*
Exporting build configuration macros to doxygen,
so they get documented.
*/
#ifdef IN_DOXYGEN
# define EXCLUSIVE_MACRO_ONE
# define EXCLUSIVE_MACRO_TWO
# define EXCLUSIVE_MACRO_THREE
#endif /* IN_DOXYGEN */
Then the documentation for these macros is picked up properly.
If you don't want to change the source, you can add EXCLUSIVE_MACRO_ONE and friends in PREDEFINED, instead of setting EXTERNAL_MACRO.
Inspired by answer.
PROBLEM: We have an existing header that, based on an external macro (provided by build system), defines one of several exclusive macros during compilation. Since only one of the compile-time macros is defined (for each individual build), it is difficult to add Doxygen documentation to all of the exclusive options.
// DEFINED_EXTERNALLY is a macro provided by the build system (e.g. via -D). It is defined as 1, 2, or some other natural number.
// Based on DEFINED_EXTERNALLY we want to define one of several exclusive DEFINED_HERE_... macros (e.g. DEFINED_HERE_1, DEFINED_HERE_2, and DEFINED_HERE_OTHER).
// First, we check that none of the DEFINED_HERE_... macros is defined yet.
#if defined(DEFINED_HERE_1) || defined(DEFINED_HERE_2) || defined(DEFINED_HERE_OTHER)
# error "Conflict: macro DEFINED_HERE_... is already defined!"
#endif
// Then, we define one, and only one, of the DEFINED_HERE_... macros.
#if DEFINED_EXTERNALLY == 1
# define DEFINED_HERE_1
#elif DEFINED_EXTERNALLY == 2
# define DEFINED_HERE_2
#else
# define DEFINED_HERE_OTHER
#endif
SOLUTION: We temporarily define all variants of the DEFINED_HERE_... macros, together with their documentation. This will cause Doxygen to generate documentation for all of them. We then undefine all of the variants and resume normal macro definition logic.
As a result, we will have documentation for all variants yet only one of them will be defined during compilation as was the case before adding the documentation.
Original code
// DEFINED_EXTERNALLY is a macro provided by the build system (e.g. via -D). It is defined as 1, 2, or some other natural number.
// Based on DEFINED_EXTERNALLY we want to define one of several DEFINED_HERE_... macros (e.g. DEFINED_HERE_1, DEFINED_HERE_2, and DEFINED_HERE_OTHER).
// First, we check that none of the DEFINED_HERE_... macros is defined yet.
#if defined(DEFINED_HERE_1) || defined(DEFINED_HERE_2) || defined(DEFINED_HERE_OTHER)
# error "Conflict: macro DEFINED_HERE_... is already defined!"
#endif
New inserted code to generate documentation
/// \brief Value 1.
/// \details It does the following...
#define DEFINED_HERE_1
#undef DEFINED_HERE_1
/// \brief Value 2.
/// \details It does the following...
#define DEFINED_HERE_2
#undef DEFINED_HERE_2
/// \brief Other value.
/// \details It does the following...
#define DEFINED_HERE_OTHER
#undef DEFINED_HERE_OTHER
Original code
// Then, we define one, and only one, of the DEFINED_HERE_... macros.
#if DEFINED_EXTERNALLY == 1
# define DEFINED_HERE_1
#elif DEFINED_EXTERNALLY == 2
# define DEFINED_HERE_2
#else
# define DEFINED_HERE_OTHER
#endif
NB no change to the default Doxygen settings is required
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
PREDEFINED =
EXPAND_AS_DEFINED =

Is it possible to define macro inside macro?

I want to use macro parameter like this:
#define D(cond,...) do{ \
#if cond \
#define YYY 1 \
#else \
#define YYY 0 \
} while(0)
Is it possible?
UPD
Maybe when sources will be preprocessed twice: gcc -E source.c | gcc -xc - next will work:
#define D(cond,...) #define YYY cond&DEBUG
#if YYY
#define D(...) printf( __VA_ARGS__ )
#else
#define D(...)
#endif
No, because C 2011 [N1570] 6.10.3.4 3 says, about macro replacement, “The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one,…”
This is not possible. Read about the GNU cpp preprocessor and the C11 standard (i.e. n1570), and check here. The C preprocessor is (conceptually at least) run before the rest of the compiler (which gets the preprocessed form of your translation unit). BTW, for a file foo.c you could use gcc -C -E foo.c > foo.i (using GCC) to get inside foo.i its preprocessed form, and you can inspect that foo.i -since it is a textual file- with a pager or an editor.
However, a .c file can be generated (generating C code is a common practice, at least since the 1980s; for example with yacc, bison, rpcgen, swig, ....; many large software projects use specialized generators of C or C++ code...). You might consider using some other tool, perhaps the GPP preprocessor (or GNU m4) or some other program or script, to generate your C file (from something else). Look also into autoconf (it might have goals similar to yours).
You may want to configure your build automation tool for such purpose, e.g. edit your Makefile for GNU make.
No, this is not possible.
During translation, all preprocessing directives (#define, #include, etc.) are executed before any macro expansion occurs, so if a macro expands into a preprocessing directive, it won't be interpreted as such - it will be interpreted as (invalid) source code.
As pointed out by others this is not possible but there is a work around:
int YYY;
/* global scope variables are sometimes considered bad practice... */
#define D(cond,...) do{ \
if (cond) { \
YYY = 1; \
} \
else { \
YYY = 0; \
} \
} while(0)
Use an optimizing flag (ex: gcc/clang -O3) and it will replace the dead code as if it was a macro. Obviously you may want to change the type of YYY but you seem to use it like a boolean.
No, you cannot. The C preprocessor cannot know what is going to occur during runtime.
The preprocessor goes through the program before it is even compiled and replaces every macro defined with its assigned value.
This is some poor man's code generation, for when integrating another tool to the project is overkill.
Define a macro like this, expanding for your needs:
#define NESTED /* Comment out instead of backslash new lines.
*/ /*
*/ UNDEF REPLACED /*
*/ /*
*/ IFDEF CONDITION /*
*/ DEFINE REPLACED 1 /*
*/ ELSE /*
*/ DEFINE REPLACED 0 /*
*/ ENDIF
Your version of NESTED can be a function-like macro, and REPLACED can have a more elaborated body.
Leave CONDITION and the directive named macros without a definition.
DEFINE CONDITION to control which value NESTED gets on compilation, similarly to normal #ifdef usage:
DEFINE CONDITION
NESTED
int i = REPLACED; //i == 1
UNDEF CONDITION
NESTED
int z = REPLACED; //z == 0
Source code that uses NESTED and the other macros will not compile. To generate a .c or .cpp file that you can compile with your chosen options, do this:
gcc -E -CC source.c -o temporary.c
gcc -E \
-DDEFINE=\#define -DUNDEF=\#undef \
-DIFDEF=\#ifdef -DELSE=\#else -DENDIF=\#endif \
temporary.c -o usableFile.c
rm temporary.c #remove the temporary file
-E means preprocess only, not compile. The first gcc command expands NESTED and all normally defined macros from the source. As DEFINE, IFDEF, etc. are not defined, they and their future arguments remain as literal text in the temporary.c file.
-CC makes the comments be preserved in the output file. After the preprocessor replaces NESTED by its body, temporary.c contains the directive macros in separate lines, with the comments. When the comments are removed on the next gcc command, the line breaks remain by the standard.
# is accepted in the body of a macro that takes no arguments. However, unlike macros, directives are not rescaned and executed on expansion, so you need another preprocessor pass to make nested defines work. All preprocessing related to the delayed defines needs to be delayed too, and made available to the preprocessor at once. Otherwise, directives and arguments needed in a later pass are consumed and removed from the code in a previous one.
The second gcc command replaces the -D macros by the delayed directives, making all of them available to the preprocessor starting on the next pass. The directives and their arguments are not rescaned in the same gcc command, and remain as literal text in usableFile.c.
When you compile usableFile.c, the preprocessor executes the delayed directives.

Processing some directives leaving others

I use to go through C code having lot of #ifdef, #if and #endif directive which keep some portion active and some portion inactive depending on some variables are defined or not. I searched for something that can process them to generate final C code. But the preprocessing also does the same for #include and #define. But I want to keep them.
So, is there any thing to preprocess these files or project with some filtering?
There are a series of programs that can do that:
unifdef - the oldest
sunifdef (Son of Unifdef)
coan (Son of sunifdef)
I've used sunifdef extensively on some very contorted code and have never found it to make a mistake. I'm ready to start using coan now, though it will still be under scrutiny for a while. Version 4.2.2 was released today, 2010-12-20.
See also: SO 525283
I assume you're using gcc.
If you mean all #includes, I think you need to remove them, expand the resulting file with gcc -E then add the #includess back.
If you mean only the standard headers, the option -nostdinc may help you do what you want
user#host:~/test/tmp$ cat 4437465.c
#include <stdio.h>
#ifndef OUTPUT_TYPE
#define OUTPUT_TYPE 1
#endif
int main(void) {
#if OUTPUT_TYPE == 1
printf("output type 1\n");
#elif OUTPUT_TYPE == 2
printf("output type 2\n");
#else
printf("default output type\n");
#endif
return 0;
}
user#host:~/test/tmp$ gcc -DOUTPUT_TYPE=2 -nostdinc -E 4437465.c
# 1 "4437465.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "4437465.c"
4437465.c:1:19: error: no include path in which to search for stdio.h
int main(void) {
printf("output type 2\n");
return 0;
}
what you want might be actually a bad idea, as there might be definitions coming from included files, describing your architecture, for example... But any modern IDE can visualize the #if preprocessor directives.
We used a custom parser to achieve what you intend to do. Lex & YACC
would be a good start for such tool.
On a side note, it was a really painful way to manage different versions of binaries in a large code base. If it's possible, try to isolate your optionnal code parts in different libraries that can or cannot be included in your final deliverable as a dynamic or static library.

Precedence of -D MACRO and #define MACRO

If I have a C file foo.c and while I have given -DMACRO=1 as command line option for compilation. However, if within the header file also I have
#define MACRO 2
Which of these will get precedence?
I'm making an assumption of what you're doing, but if you'd like to supply from the command-line a non-default value for that macro, try this for the macro definition:
#ifndef MACRO
#define MACRO 2
#endif
That way if the MACRO has already been defined (via command-line parameter) it will neither be redefined nor result in an error.
The command line options apply ahead of any line read from a file. The file contents apply in the order written. In general, you will get at least a warning if any macro is redefined, regardless of whether the command line is involved. The warning may be silenced if the redefinition doesn't matter, perhaps because both definitions are identical.
The right way to answer a question like this is to build a small test case and try it. For example, in q3965956.c put the following:
#define AAA 2
AAA
and run it through the C preprocessor, perhaps with gcc -E:
C:>gcc -DAAA=42 -E q3965956.c
# 1 "q3965956.c"
# 1 ""
# 1 ""
# 1 "q3965956.c"
q3965956.c:1:1: warning: "AAA" redefined
:1:1: warning: this is the location of the previous definition
2
C:>
You can see from the output that the macro expanded to the value given by the #define in the file. Furthermore, you can see from the sequence of # directives that built-in definitions and the command line were both processed before any content of line 1 of q3965956.c.
Defines are stored in order the compiler sees them, and when the compiler encounters a new macro with the same name, it overwrites the previous macro with the new one (at least this is the case in gcc). GCC will also give you a warning when this happens.
You'll get an error for macro redefinition. Obviously -D gets defined first (before the source file is parsed rather than after) or it would have no use. The #define is then a redefinition.
manual says: first all -D and -U are evaluated in order and then all -includes (under section -D)
best way: try it out.

Resources