16

I was going through the GCC man page, I found the following line:

 file.i
           C source code that should not be preprocessed.

I know that running gcc -E foo.c stops the compiler after preprocessing; but what is the real world application of creating .i files.

Also is there a way of generating a .i files other than gcc foo.c -E > foo.i?

Sathish
  • 3,740
  • 1
  • 17
  • 28
Nihal Harish
  • 980
  • 5
  • 13
  • 31
  • 2
    Another way is `gcc --save-temps -o foo foo.c` – David Ranieri Aug 05 '14 at 11:47
  • 7
    One real-world use is in reporting compiler bugs. You send the `.i` file that triggers the bug, so it can be reproduced by someone who doesn't have your headers. https://gcc.gnu.org/bugs/#need –  Aug 05 '14 at 12:22

2 Answers2

20

The .i files are also called as "Pure C files". In preprocessing stage

  1. Header files will be included.

  2. Macros will be replaced.

  3. Comments are removed.

  4. Used for conditional compilation. If you look at the .i file you can see these things.

Command to generate .i file is-

gcc -E foo.c -o foo.i
Sathish
  • 3,740
  • 1
  • 17
  • 28
10

A file.i file is:

C source code that should not be preprocessed.

Source: man gcc then press the / key to search, and search for "\.i".
Detailed Steps: man gcc, then press the / key to search, then type in \.i, then press the Enter key, then press the n key repeatedly until you find it.

What this means is that a .i file is preprocessed source code, so it has already been preprocessed. Therefeore, it already contains:

  1. all header files included
  2. macros replaced
  3. and comments removed

...as stated by @Sathish in his answer.

You'll also notice a ton of special "comments" added by gcc that now begin with the # character, such as these:

# 1 "main.c"  
# 1 "<built-in>"  
# 1 "<command-line>"  
# 1 "/usr/include/stdc-predef.h" 1 3 4  
# 1 "<command-line>" 2  
# 1 "main.c"  
# 44 "main.c"  
# 1 "/usr/include/stdio.h" 1 3 4  
# 27 "/usr/include/stdio.h" 3 4  
# 1 "/usr/include/features.h" 1 3 4  
# 374 "/usr/include/features.h" 3 4  
# 1 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 1 3 4  

I don't know what those are nor what they do. Someone please tell me if you know.

Note that a simple program such as this:

#include <stdio.h>

int main()
{
    printf("hello world\n");

    return 0;
}

Compiled with this:

gcc -Wall -std=c99 -O0 -save-temps=obj main.c -o ./bin/main

Will produce a main.i file that is about 682 lines long, with the main() function shown above being right at the very end.

How to generate all intermediate files, including the .i files:

My preference is to generate all intermediate files (.i, .o, .s, rather than just the .i file using -E) all at once in a local bin folder in the project by using the gcc -save-temps=obj option like this:

mkdir bin
gcc -save-temps=obj foo.c -o ./bin/foo

Now you have the following files in the "foo/bin" directory:

foo     # compiled binary program (AKA: combined "object file", 
        # "executable", "binary", "program", or "machine code")
foo.i   # intermediate, preprocessed C file  
foo.o   # individual object file  
foo.s   # assembly file

Run the program of course with:

./bin/foo

Notes about "object files" and "executables"

Note that the final output, the foo executable file, is called the "compiled binary program", "program", (combined) "object file", "executable", "binary", or just "machine code", or "ones and zeros" (10101010). It is an object file in object file format, as are the individual *.o object files which are combined into one by the linker to create it. The linker combines all *.o object files into one in order to make the final foo executable, or combined object file.

The GNU linker (ld) manual states it as follows. See section "3.1 Basic Linker Script Concepts": https://sourceware.org/binutils/docs/ld/Basic-Script-Concepts.html#Basic-Script-Concepts (emphasis added, as well as content in square brackets []):

3.1 Basic Linker Script Concepts

We need to define some basic concepts and vocabulary in order to describe the linker script language.

The linker combines input files [individual *.o object files] into a single output file. The output file and each input file are in a special data format known as an object file format. Each file is called an object file. The output file is often called an executable, but for our purposes we will also call it an object file. Each object file has, among other things, a list of sections. We sometimes refer to a section in an input file as an input section; similarly, a section in the output file is an output section.

For more info. on object files, you can also see two of my other answers here:

  1. How do I find out at compile time how much of an STM32's Flash memory and dynamic memory (SRAM) is used up?
  2. Convert binutils `size` output from "sysv" format (`size --format=sysv my_executable`) to "berkeley" format (`size --format=berkeley my_executable`)
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265