Other answers are explaining how to make gcc
read C code from stdin, but notice that in practice
it is not worth the effort to avoid dealing with C files.
(I am guessing you are using some POSIX operating system like Linux; if not, adapt my answer to your OS and compiler)
Emitting C code automatically is usual practice (and many academic programming languages are compiling to C, and many builds are using generated C code, e.g. from bison). But there is no much gain to use pipes and stdin, because a C compiler takes a lot of time (notably for optimization, which you often want, e.g. by compiling with gcc -O2
).
So my recommendation is to put the generated C code in a genuine file (perhaps some temporary one which should be removed later appropriately). That file could be on some tmpfs file system if disk performance is an issue (and in practice it never is for gcc
compiled source code), and that file could be temporary (e.g. removed later) if you want it to.
Notice that the gcc
program is generally using temporary files internally itself (e.g. for generated assembler files or object files). You'll see them if you add -v
to your gcc
compilation command, e.g. if you compile foo.c
with gcc -v foo.c -o fooprog
. So there is no practical reason to avoid a C source file (since gcc
uses temporary files anyway!).
If you want to generate code on the fly in a running program, you could generate temporary C code then compile it as a temporary plugin (with position-independent code) then dynamically load that plugin (e.g. using dlopen(3) & dlsym(3) on Linux); but you could also use JIT compiling libraries like GCCJIT or LLVM or asmjit, etc.... Of course this requires some support from your operating system (e.g. to grow your virtual address space): in pure standard C11 (read n1570), the set of functions is fixed at build time since defined in the union of your translation units (the set of .c
files comprising your program), and you cannot generate code at runtime.
If you want to generate some C program in some shell script, better use temporary files, e.g. with tempfile
, mktemp
etc... (and use trap
builtin on EXIT
and on TERM
signal to remove the temporary files when the script terminates).
If you generate some temporary C code in your build, good build automation programs (e.g. GNU make
or ninja
) can be configured to remove these temporary C files (e.g. read about intermediate files for make
).
Look also into homoiconic programming languages like Common Lisp. For example SBCL is compiling into machine code at every REPL interaction.