I need to expand a single preprocessor directive, for example:
Having a source file and two headers, I want to expand only one define from one specific header, leaving all other include and define intact.
The main idea is that, given code similar to this:
defs.h:
#define FOO(X,op) int X(int a,int b) { return a op b; }
other_file.h:
#define ONE 1
#define TWO 2
#define THREE 3
#define FOUR 4
#define FIVE 5
main.c:
"file: main.c "
#include <stdio.h>
#include "defs.h"
#include "other_file.h"
FOO(add,+)
FOO(sub,-)
FOO(mul,*)
FOO(div,/)
int main()
{
printf("%d\n",add(ONE,TWO));
printf("%d\n",sub(THREE,FOUR));
printf("%d\n",mul(FIVE,FIVE));
printf("%d\n",div(25,FIVE));
return 0;
}
I would have the main.c output with the same includes, but with FOO expanded to the created functions. I known the example is silly, but I intend to run it on a larger code database.
The motivation to do it is to run cccc in functions that are defined within macros. The easiest way to run it is to expand those macros. I also welcome alternative ways to do this.
You can play with the -E, -nostdinc, -nostdinc++ and -fpreprocessed parameters of GCC.
For your example, you can run:
gcc -E -nostdinc -fpreprocessed main.c
And the output would be:
# 1 "main.c"
#include <stdio.h>
#include "defs.h"
#include "other_file.h"
FOO(add,+)
FOO(sub,-)
FOO(mul,*)
FOO(div,/)
int main()
{
printf("%d\n",add(ONE,TWO));
printf("%d\n",sub(THREE,FOUR));
printf("%d\n",mul(FIVE,FIVE));
printf("%d\n",div(25,FIVE));
return 0;
}
If the headers are not that complex, like in your example, you can force gcc to preprocess the whole file even with some missing macros. E.g.:
cp other_file.h other_file.h_orig
echo "" > other_file.h
gcc -E -nostdinc main.c
Output:
# 1 "main.c"
# 1 "<command-line>"
# 1 "main.c"
main.c:1:19: error: no include path in which to search for stdio.h
#include <stdio.h>
^
# 1 "defs.h" 1
# 3 "main.c" 2
# 1 "other_file.h" 1
# 4 "main.c" 2
int add(int a,int b) { return a + b; }
int sub(int a,int b) { return a - b; }
int mul(int a,int b) { return a * b; }
int div(int a,int b) { return a / b; }
int main()
{
printf("%d\n",add(ONE,TWO));
printf("%d\n",sub(THREE,FOUR));
printf("%d\n",mul(FIVE,FIVE));
printf("%d\n",div(25,FIVE));
return 0;
}
It will remove the header inclusions, though... and will print you an error on std headers, that goes to stderr instead of stdout.
This works for your small example, but on larger codebase you may face some problems...
Here is a brief summary of the parameters from the manual (of GCC 4.8.2) :
-E: Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which
is sent to the standard output.
-fpreprocessed: Indicate to the preprocessor that the input file has already been preprocessed. This suppresses things like macro
expansion, trigraph conversion, escaped newline splicing, and
processing of most directives.
-nostdinc: Do not search the standard system directories for header files. Only the directories you have specified with -I options.
-nostdinc++: Do not search for header files in the standard directories specific to C++, but do still search the other standard
directories.
Our DMS Software Reengineering Toolkit with its C Front End will do this.
DMS provides general purpose program parsing/analysis infrastructure. The C Front End builds on that to provide a full-function C front, complete with C preprocessor.
Normally, the DMS C preprocessor acts just like the standard one: it preprocesses everything, producing a substituted stream of tokens. Unusually, it can be configured to NOT process conditionals (this is all-or-nothing), or to expand only designated macros. In particular, it accepts a custom #pragma that declares that a macro should (not) expand.
It isn't clear to me that this is worth the effort. Yes, a metrics tool might produce more accurate answers in certain places where some macro is heavily used, if you believe that the macro should be non-opaque. If you think the macro is essentially just a funny-looking subroutine, then expanding this macro is like inlining a function body, and you would not do that to compute metrics.
Related
When I include another source(I.e stdio.h) the preprocessor is smart enough to include only the functions that I am using in my code?
Example: Assuming this small program, would be ease to include only what I am using, and what the printf functions uses, including them recursively, but what about bigger programs?
#include <stdio.h>
int main(void) {
printf("Hello World\n");
return 0;
}
No. On the contrary:
#include performs textual replacement: it opens the file and copies all1 of its contents into your main C file. In the process it executes all preprocessor instructions in the included file. Amongst other things, this means that it will recursively include all files that are #included in the header.
#include does not know and does not care which part of the included file you end up using.
1 As mentioned, preprocessor instructions are executed in the included file. This can modify what gets included. For example, assume the following header file header.h:
#ifndef HEADER_H
#define HEADER_H
#ifdef NDEBUG
# define LOG(...) ((void) 0)
#else
# define LOG(...) log_message(__FILE__, __LINE__, __VA_ARGS__)
inline void log_message(const char* filename, int line, ...) {
// Logging code omitted for brevity.
}
#endif
// other stuff
#endif
Now, if your main.c file looks as follows:
#define NDEBUG
#include "header.h"
int main(void) {
// …
LOG("hello");
}
… then, after preprocessing, your main.c file would looks something like this (I’m omitting some irrelevant stuff):
# 1 "main.c"
# 1 "./header.h" 1
# 13 "./header.h"
// other stuff
# 3 "main.c" 2
int main(void) {
// …
((void) 0);
}
… in other words, only the part of header.h that corresponds to #ifdef NDEBUG was included, not the part in the #else clause. If we had included header.h without defining NDEBUG, then the included header code would have contained the definition of log_message.
As others have said, #include will paste verbatim the entire file you are targeting. However you normally include headers, which tend to look like
extern int a (int b);
extern char * c (void);
static inline int d (int e, int f) {
...
}
extern void * g (void * h);
...
The code above occupies exactly zero memory (unless you start using one of the inline functions), since it is entirely composed of instructions for the compiler and nothing else.
I am a newbie to C and C++ language, I have a question about header files in C:
a.h
#define HELLO (1)
typedef struct
{
int a;
int b;
} hello;
b.h
#include "a.h"
#define NUMBER (3)
main.c
#include "b.h"
in main.c, does struct and macro defined in a.h can be used in main.c?
Sure you can use both Struct and MACROS in the main.c
You need to be aware of the C Compilation Process, Before main.c is being compiled or linked, there is the pre-processor step:
Preprocessor:
The input to this phase is the .c File and .h Files
The preprocess process the preprocessor keywords like #define, #ifdef, #include, etc. and generate a new .pre file or .i file after the text replacement process.
The output of this phase is a C Code without any preprocessor keyword.
So the main.c will actually look like this:
#define HELLO (1)
typedef struct
{
int a;
int b;
} hello;
#define NUMBER (3)
And then replace all macros, here you don't use HELLO or NUMBER, so the pure c main file will be:
typedef struct
{
int a;
int b;
} hello;
Yes, it can be used. That is the sole purpose of #includeing of header files.
For more information, you can see the preprocessed version of code. Use
gcc -E <filename.c> //main.c, in this case
There you can see the presence of the struct and MACROS definde in the included header files.
Yes, #include directives themselves appearing in included files have their normal effect, up to an implementation-defined limit on the number of levels of inclusion. The "normal effect" is equivalent to textual interpolation -- that is, there is no separate scoping for the contents of included files -- so any declaration appearing in any directly or indirectly included file is visible to all code following the point of inclusion.
Yep, #include statements can chain multiple files together. #include literally copies and pastes the contents of one file into another, so you can think of it as a one-after-another effect.
i have the following files
(its pseudo code, and i know the define, undef is ugly, but i would need it for some project)
if i compile those files and link them together - it seems to work - that in file3, file1 - MYVAL == 1
is it safe to assume this, that the preprocessor stuff is done file-by-file?
conf.h:
#define MYVAL 1
src1.c
#include "conf.h"
int maint(int argc, char ** argv) {
printf("%d", MYVAL);
}
src2.c
#include "conf.h"
void demo() {
#undef MYVAL
#define MYVAL 2
printf("%d", MYVAL);
}
src3.c
#include "conf.h"
void demo2() {
printf("%d", MYVAL);
}
regards
Preprocessing is done per translation unit before the compilation phase (so way earlier than the linkage phase). In your case the preprocessor will expand that macro in each of your .c files individually based on your inclusion of the conf.h header file.
is it safe to assume this, that the preprocessor stuff is done file-by-file?
Basically in your case yes. Each of your .c files is a distinct translation unit. (Unless they start including each other or something) They are preprocessed separately, compiled and then their objects get linked together.
When you #include "conf.h" its code is placed instead of this line. This is the preprocessor's work. So, this define sentence is placed in each file.
But if you do #define work(n) funcCall((n)) and work(5); then, it'll fail if funcCall is not defined in any of your files.
Yes, the preprocessor is used for each source file. It generates a preprocessed file from the source file and all include files that is actually passed to the C compiler.
When you #define something in a include file it gets in the preprocessed file. #defines in other source file doesn't care.
I have a Linux standard header file e.g.
/usr/src/linux-headers-3.2.0-35/include/linux/usbdevice_fs.h
which contain define statements as follows:
#define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32)
#define USBDEVFS_DISCARDURB _IO('U', 11)
#define USBDEVFS_REAPURB _IOW('U', 12, void *)
What does '_IOR', '_IO' and '_IOW' mean? What value is actually given e.g. to USBDEVFS_DISCARDURB?
They define ioctl numbers, based on ioctl function and input parameters.
The are defined in kernel, in include/asm-generic/ioctl.h.
You need to include <linux/ioctl.h> (or linux/asm-generic/ioctl.h) in your program. Before including
/usr/src/linux-headers-3.2.0-35/include/linux/usbdevice_fs.h
You can't "precompile" this values (e.g. USBDEVFS_DISCARDURB), because they can be different on other platforms. For example, you are developing your code on plain old x86, but then someone will try to use it on x86_64/arm/mips/etc. So you should always include kernel's ioctl.h to make sure, you are using right values.
These are also macros defined elsewhere.
In general if you want to see your code after pre-processor has been computed use
gcc -E foo.c
this will output your code pre-processed
For example:
foo.c
#define FORTY_TWO 42
int main(void)
{
int foo = FORTY_TWO;
}
will give you with gcc -E foo.c:
int main(void)
{
int foo = 42;
}
I'm trying to figure out how to build a variable string for the #include statement using GCC.
The idea is that for each source module I have written, I want to include as a header, a dynamically generated C source, that was created earlier in the build process.
Generating this file is not an issue. Including it, unfortunately, is.
What I have so far is (identities.h):
// identities.h
# define PASTER2(str) #str
# define PASTER(str) PASTER2(str ## .iden)
# define EVALUATOR(x) PASTER(x)
# define IDENTITIES_FILE EVALUATOR(__FILE__)
# include IDENTITIES_FILE
Ideally, this would be used like so (main.c):
//main.c
# include "identities.h"
int main() {return 0;}
Which would be expanded in a single pass by the preprocessor before compilation to yield:
//main.c (preprocessed)
# include "main.c.iden"
int main() {return 0;}
The two levels of indirection I'm using (PASTER and EVALUATOR) are a result of this post.
Unfortunately, this is not working and I am left with the error:
obj/win32/dbg/main.o
In file included from main.c:1:0:
identities.h:42:1: error: #include expects "FILENAME" or <FILENAME>
I think the problem is that the include statement is missing quotes.. Any ideas?
This is actually done in the Linux source tree; See line 100 of compiler-gcc.h.
#define __gcc_header(x) #x
#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h)
#define gcc_header(x) _gcc_header(x)
#include gcc_header(__GNUC__)
I'm trying to figure out how to build a variable string for the #include statement using GCC.
This token pastes the value of __GNUC__ to a string; "linux/compiler-gcc" __GNUC__ ".h" and then stringifies the result. This maybe a gcc pre-processor extension.
Here is an example,
t1.h
#define FOO 10
t2.h
#define FOO 20
a.c
#ifndef VERSION
#define VERSION 1
#endif
#define __gcc_header(x) #x
#define _gcc_header(x) __gcc_header(t##x.h)
#define gcc_header(x) _gcc_header(x)
#include gcc_header(VERSION)
#include <stdio.h>
int main(void)
{
printf("FOO is %d\n", FOO);
return 0;
}
Here are two compiles,
g++ -o a a.cc
g++ -DVERSION=2 -o a a.cc
The output of either compile gives expected result.
As with the Linux source, you can key off of gcc pre-defined values. echo | g++ -dM -E - will give a list.
For your case, you can use the makefile to pass a define to the compile to allow dynamic inclusion of the generated header without altering the source. But then a simple alternative is just to run sed, etc on a template source file and replace it with the known include name.
Either technique is good for generating test fixtures, etc. However, for compiler feature discovery, this is a better method. For programmers who use IDEs, this might be their only choice.
I am fairly certain you can't do what you want, __FILE__ returns a string and ## works on tokens and there is no CPP string concat preprocessor macro. Normally this is gotten around due to the fact that two strings in succession e.g.
"Hello" " World"
will be treated as a single string by the C++ parser. However, #include is part of the preprocessor, and thus cannot take advantage of that fact.
Old answer:
Why are you doing this
{ #str, str ## .iden }
I'm certain that's not preprocessor syntax; what do you hope to achieve via that? Have you tried just:
str ## .iden
A '{' could explain the error you are getting.
What about BOOST_PP_STRINGIZE from the Boost Preprocessor library . It is specifically made to add quotes around a name.
Skipping the whole inclusion syntax thing for a while, I don't understand what your code is trying to do. You say:
# define PASTER(str) { #str, str ## .iden }
You give it main.c and expect "main.c.iden", but that returns {"main.c", main.c.iden }.
Are instead you looking for this?
#define PASTER2(str) #str
#define PASTER(str) PASTER2(str ## .iden)
You cannot use preprocessor like this. You have to supply a filename to the #include directive, it can't be some other macro.