Some differences stem from tcc being unfinished. Others are inherent in the wildly different compiler implementations.

TCC is a simple translator, converting C source into the equivalent object code. The main goals of tcc are:

The third goal remains a work in progress.

Note that optimized output is _not_ one of these goals. As a simple translator, TCC does not optimize the resulting binaries much. TCC's output is generally about twice the size of what a compiler like icc or gcc would produce. We have some simple optimizations like constant propogation, and hope to add dead code elimination, but there's no "intermediate format" allowing major rearrangements of the code.

If somebody wanted to implement an optimizer for tcc, we'd be happy to take it as long as it was cleanly separated from the rest of the code. However, if you want a big and complicated compiler, there are plenty out there already.

TCC is a single self-contained program. It does not use an external linker, but produces ELF files directly from C source and ELF file inputs such as shared libraries.

In theory, four packages (uClibc, tcc, busybox, and the Linux kernel) could provide a complete self-bootstrapping development environment. (In practice, we're still working on tcc.)

Piotr Skamruk points out that if you want assembly output, you can use objdump, ala:

  tcc -c somefile.c
  objdump -dtsr somefile.o

Function argument evaluation order is explicitly undefined (c99 spec section 3.19 #2). TCC evaluates function arguments first to last. Some compilers (like gcc) evaluate function arguments last to first.

The following program would produce different output in tcc and gcc:


int woot(int a)
  return a;

int main(int argc, char *argv[])
  printf("%d %d %d",woot(1),woot(2),woot(3));

  return 0;

TCC's error checking isn't as elaborate as some compilers. Try a project like splint or sparse if you want lots of warnings.