7

To call printf("Hello!"); in C from terminal I use

echo '#include<stdio.h>
void main()
{
printf("Hello!");
}' > foo.c

and then call gcc foo.c to make the output. Unfortunately, the pipelining

echo '#include<stdio.h>
void main()
{
printf("Hello!");
}' | gcc 

fails complaining for no input file. Ultimately, I want to have a script where I can compile a C command from terminal with ./script [command]. Any suggestion would be appreciated.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Masoud Ghaderi
  • 437
  • 5
  • 16
  • 1
    May I ask when you want to do this? I cannot see any use of it. – klutt Dec 28 '17 at 00:01
  • 1
    @klutt: if the C code is generated by some program, you might want to do that. But indeed, it is not worth the pain – Basile Starynkevitch Dec 28 '17 at 07:25
  • @klutt In general, pipelines are a Good Thing. In general, any program should accept input from stdin, unless it has some very good reason for not doing so. Just because you can't think of a good use for it, doesn't mean that having the general-purpose capability is not a good idea. (Now, with that said, I agree it's hard to think of a situation where you'd actually need to pipe C code into a C compiler. I implemented the symbolic link trick -- as described in by answer -- many many years ago, just for fun, but I don't think I've ever actually used it.) – Steve Summit Dec 28 '17 at 07:31
  • Probably not what the OP was looking for, but another good way to execute small scraps of C "on the fly", in shell scripts or the like, is if you happen to have a C *interpreter*. For example, having such an interpreter, I can just type `ci -c 'printf("Hello!\n");'`. – Steve Summit Dec 06 '21 at 11:46

4 Answers4

8

Yes, but you have to specify the language using the -x option. Specify input file as stdin, language as C using -xc (if you want it to be C++, use -xc++). So in your case the command would be

echo '#include<stdio.h>
void main()
{
printf("Hello!");
}' | gcc -o output.o -xc -

You can read more about Command Line Compiler Arguments: see Invoking GCC chapter.


There is also another way to do this without echo:

gcc -o output.o -xc - <<< '#include<stdio.h>
void main()
{
printf("Hello!");
}'

However, as @Basile says, it is not worth the effort to avoid dealing with C files. Check his answer for more information.

ndrwnaguib
  • 5,623
  • 3
  • 28
  • 51
3

I have done this in the past by doing things like

ln -s /dev/stdin stdin.c

Now stdin.c is a symlink to /dev/stdin, i.e. a magic file "containing" anything I type or pipe to it. But the filename ends in .c, so any C compiler should treat it as a C file. Things like

(echo '#include <stdio.h>'
 echo 'int main(void) { printf("Hello, world!\n"); }') |
    cc stdin.c

work just fine.

(Obviously this assumes you're using a Unix-like system with symbolic links and /dev/stdin.)


Addendum: Obviously this also assumes you're using a one-pass C compiler! I believe I first tried this trick with /dev/tty and an older, two-pass compiler (probably Ritchie's original, although I no longer remember for sure), and it "worked fine" there also, as long as you typed the identical input twice. :-) (Seriously. main(){printf("Hello, world!\n");}^Dmain(){printf("Hello, world!\n");}, with a control-D in the middle.)

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
3

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.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • It's true that compiling C code from stdin is impractical, but in arguing so strenuously here against the possibility, I can't help noticing that you've argued pretty strongly against the notion of pipes at all! My own reading of the Unix Philosophy (which is admittedly overzealous at times) holds that you should *always* be able to pipe things, that you should *never* have to resort to temporary files. (Now, with that said, if a C compiler which "violates" the Unix philosophy were written by the same people who first established the philosophy, obviously I'm not going to complain too much.) – Steve Summit Dec 06 '21 at 11:53
1

without echo something to pipeline, you can do like this:

gcc -x c - <<eof
#include<stdio.h>
void main()
{
printf("Hello!");
}
eof
jianyongli
  • 1,131
  • 12
  • 10