First, as for the cross-compiler, that's not a matter of using a different compiler, but of using a separate
build of the GCC compiler. The wiki covers the process for creating a
GCC Cross Compiler in detail (follow the given link).
Regarding
void main(): the standard for C has always been that
int main() is the correct, portable form. This was necessary because Unix, which was C's native environment, required every program to have an integer return value for passing error messages to the shell. However, in the original K&R form, an
int return with a value of 0 (which in Unix indicates 'program completed with no errors') was the default for all functions, so most programs wrote it as:
Furthermore, the compilers of the time did little type checking, and would allow a function to return with or without a value regardless of how it was declared.
When the language was formally standardized in 1989, it was sensibly argued that a default
int was a problem for anything that didn't have a return value, so
void was added for non-returning functions, and returns were required to be type checked. Only a
void function could now end without an explicit
return statement.
However, when they were defining the behavior of
main(), it was pointed out that some OSes didn't support a program return the way Unix did, and that it would present an issue with embedded code as well. Thus, it was ruled that a compiler could optionally allow a
void main(), but that this would be non-standard - it was intended that only compilers for systems where a program return was a problem would use it, and
int main() would be used everywhere it could be. A
compliant C compiler would still need to use
int main().
Unfortunately, this was worded in a tremendously confusing fashion. As a result, a lot of MS-DOS compiler developers decided that this stipulation applied to them, even though MS-DOS did support program returns after version 2.x (which borrowed a lot of things from Unix such as pipes and directories), and they didn't get that this moved them out of compliance. Thus, there was a proliferation of programs that used
void main(), and there was massive confusion about the subject - I recall being told that
void was the new standard when I was learning C, and didn't get the full story until much later.
Confusing this further was the fact that in C++,
void main() was an error from the start, but several non-compliant compilers allowed it.
The early 16-bit Turbo C and C++ compilers were particularly problematic about this, because they were based on a draft of the C standard, not the actual released version, and so had a huge pile of incompatibilities with the actual C89 standard, as well as dumping several non-standard libraries into the mix without mentioning in the manuals that they weren't portable (
<console.h> is the worst offender in this).
(They are also problematic for C++ specifically because C++ wasn't standardized yet, so they were free to interpret Stroustrup's book any way they liked. However, the way that the standard library headers are named was changed when that language was standardized in 1998, meaning that any C++ code written for older compilers needed to be changed when porting to something newer, and confusing the heck of students who learned on older versions. But that's a separate issue.)
Worse still, several countries (most notably India and Pakistan) standardized on those compilers very early on, and still use them to this day despite their age (release dates 1988 and 1990, respectively) and reliance on MS-DOS support. Students are still taught to use those problematic features, even though no modern compiler supports them.
Eventually, the C99 standard revision deprecated
void main(), and later still it was removed in C11. However, by this time the damage had been done.
The change in the standard also means that programs which have no return value, such as embedded systems or operating systems, need to use a non-standard entry point, rather than
main(). Since
main() usually also does a number of other things in a hidden program prefix/header on most systems, using
main() for such things was a poor choice anyway, so everyone agreed that requiring
int main() wouldn't be a problem after all. Thus, the recommendation to use something such as
void _entry() or
void _kmain() instead.
Anyway, the lesson is that it was always wrong, but for a time a lot of people didn't know that.