Some differences stem from tinycc being unfinished. Others are inherent in the wildly different compiler implementations.
Tinycc is a simple translator, converting C source into the equivalent object code. The main goals of tinycc are:
All three goals need improvement.
Note that optimized output is _not_ one of these goals. As a simple translator, Tinycc does not optimize the resulting binaries much. Tinycc'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 tinycc, 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.
Tinycc 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, tinycc, busybox, and the Linux kernel) could provide a complete self-bootstrapping development environment. (In practice, we're still working our way towards that.)
Piotr Skamruk points out that if you want assembly output, you can use objdump, ala:
tinycc -c somefile.c objdump -dtsr somefile.o
Function argument evaluation order is explicitly undefined (c99 spec section 3.19 #2). Tinycc evaluates function arguments first to last. Some compilers (like gcc) evaluate function arguments last to first.
The following program would produce different output in tinycc and gcc:
#includeint woot(int a) { printf("a=%d\n",a); return a; } int main(int argc, char *argv[]) { printf("%d %d %d",woot(1),woot(2),woot(3)); return 0; }
Tinycc's error checking isn't as elaborate as some compilers. Try a project like splint or sparse if you want lots of warnings.