What is the reason function names are prefixed with an underscore by the compiler?

Solution 1:

From Linkers and Loaders:

At the time that UNIX was rewritten in C in about 1974, its authors already had extensive assember language libraries, and it was easier to mangle the names of new C and C-compatible code than to go back and fix all the existing code. Now, 20 years later, the assembler code has all been rewritten five times, and UNIX C compilers, particularly ones that create COFF and ELF object files, no longer prepend the underscore.

Prepending an underscore in the assembly results of C compilation is just a name-mangling convention that arose as a workaround. It stuck around for (as far as I know) no particular reason, and has now made its way into Clang.

Outside of assembly, the C standard library often has implementation-defined functions prefixed with an underscore to convey notions of magicalness and don't touch this to the ordinary programmers that stumble across them.

Solution 2:

A lot of compilers used to translate C to assembly language, and then run an assembler on that to generate an object file. It's a lot easier than generating binary code directly. (AFAIK GCC still does this. But it also has its own assembler.) During this translation, function names become labels in the assembly source. If you have a function called (for example) ret, though, some assemblers can get confused and think it's an instruction rather than a label. (YASM does, for example, mostly because labels can appear pretty much anywhere and don't require colons. You have to prepend a $ if you want a label called ret.)

Prepending a character (like, say, an underscore) to the C-generated labels was a whole lot easier than writing one's own C-friendly assembler or worrying about labels clashing with assembly instructions/directives.

These days, assemblers and compilers have evolved a bit, and most people work at the C level or higher anyway. So the original need to mangle names in C is largely gone.