Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show 'preprocessed' code ignoring includes with GCC

I'd like to know if it's possible to output 'preprocessed' code wit gcc but 'ignoring' (not expanding) includes:

ES I got this main:

#include <stdio.h>
#define prn(s) printf("this is a macro for printing a string: %s\n", s);

int int(){
char str[5] = "test"; 
prn(str);
return 0;
}

I run gcc -E main -o out.c

I got:

/*
all stdio stuff
*/

int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}

I'd like to output only:

#include <stdio.h>
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}

or, at least, just

int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}

PS: would be great if possible to expand "local" "" includes and not to expand "global" <> includes

like image 632
DDS Avatar asked Feb 26 '19 17:02

DDS


People also ask

Which command is used to check preprocessed code?

If this file is called 'test. c' the effect of the preprocessor can be seen with the following command line: $ gcc -E test. c # 1 "test.

How do I create a preprocessed file in gcc?

You can get a preprocessed file in the MSVC environment by defining the value of the 'Generate Preprocessed File' property on the 'C/C++\Preprocessor' tab as shown in Figure 1. To get a preprocessed file using the GCC compiler you need to add the parameters '-E -o file_name.

Which gcc option Undefine a preprocessor macro?

4. Which gcc option undefines a preprocessor macro? Explanation: None.

What is preprocessed code in C?

Advertisements. The C Preprocessor is not a part of the compiler, but is a separate step in the compilation process. In simple terms, a C Preprocessor is just a text substitution tool and it instructs the compiler to do required pre-processing before the actual compilation.


2 Answers

I agree with Matteo Italia's comment that if you just prevent the #include directives from being expanded, then the resulting code won't represent what the compiler actually sees, and therefore it will be of limited use in troubleshooting.

Here's an idea to get around that. Add a variable declaration before and after your includes. Any variable that is reasonably unique will do.

int begin_includes_tag;
#include <stdio.h>
... other includes
int end_includes_tag;

Then you can do:

> gcc -E main -o out.c | sed '/begin_includes_tag/,/end_includes_tag/d'

The sed command will delete everything between those variable declarations.

like image 183
Mike Holt Avatar answered Oct 21 '22 08:10

Mike Holt


When cpp expands includes it adds # directives (linemarkers) to trace back errors to the original files.

You can add a post processing step (it can be trivially written in any scripting language, or even in C if you feel like it) to parse just the linemarkers and filter out the lines coming from files outside of your project directory; even better, one of the flags (3) marks system header files (stuff coming from paths provided through -isystem, either implicitly by the compiler driver or explicitly), so that's something you could exploit as well.

For example in Python 3:

#!/usr/bin/env python3
import sys

skip = False
for l in sys.stdin:
    if not skip:
        sys.stdout.write(l)
    if l.startswith("# "):
        toks = l.strip().split(" ")
        linenum, filename = toks[1:3]
        flags = toks[3:]
        skip = "3" in flags

Using gcc -E foo.c | ./filter.py I get

# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "foo.c"
# 1 "/usr/include/stdio.h" 1 3 4



# 4 "foo.c"
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);;
return 0;
}
like image 35
Matteo Italia Avatar answered Oct 21 '22 06:10

Matteo Italia