tags:

views:

319

answers:

8

This code compiles, but no surprises, it fails while linking (no main found):

Listing 1:

void main();

Link error: \mingw\lib\libmingw32.a(main.o):main.c:(.text+0x106) undefined reference to _WinMain@16'

But, the code below compiles and links fine, with a warning:

Listing 2:

void (*main)();

warning: 'main' is usually a function

Questions:

  1. In listing 1, linker should have complained for missing "main". Why is it looking for _WinMain@16?

  2. The executable generated from listing 2 simply crashes. What is the reason?

Thanks for your time.

+1  A: 

Try redefining it as int main(int argc, char *argv[])

What you have is a linker error. The linker expects to find a function with that "signature" - not void with no parameters

See http://publications.gbdirect.co.uk/c_book/chapter10/arguments_to_main.html etc

Mawg
Function main doesn't need to have arguments. int main(void) is also a perfectly valid signature. However, in C (unlike C++) int main() means that it can take any arguments, which is bad style, but AFAIK still legal.
Tronic
Agreed (sorry) See http://en.wikipedia.org/wiki/Main_function_%28programming%29#C_and_C.2B.2B But, in any case, he obviously has a linker error because no main function is declared (agreed?). Some environments (especially those for developing GUI based programs) will provide this automagically.
Mawg
+4  A: 

True, main doesn't need to be a function. This has been exploited in some obfuscated programs that contain binary program code in an array called main.

The return type of main() must be int (not void). If the linker is looking for WinMain, it thinks that you have a GUI application.

Tronic
http://www.ioccc.org/years.html#1984_mullender
jleedev
Care to explain why the downvote?
Tronic
There should be a requirement for people to comment before downvoting.
Skurmedel
+1, didn't know that :)
Daniel
+1  A: 

Case 1. is Windows-specific - the compiler probably generates _WinMain symbol when main is properly defined.

Case 2. - you have a pointer, but as static variable it's initialized to zero, thus the crash.

Nikolai N Fetissov
The compiler usually requires '_WinMain' when developing applications for windows. Many compilers have a *console* template, which requires `main`, but doesn't provide all the windowing goodies, just ol' fashioned C.
Thomas Matthews
Thomas, thanks, that much I know. Just wasn't sure if VS maybe "implants" _WinMain automatically into console programs.
Nikolai N Fetissov
+2  A: 

In most C compilation systems, there is no type information associated with symbols that are linked. You could declare main as e.g.:

char main[10];

and the linker would be perfectly happy. As you noted, the program would probably crash, uless you cleverly initialized the contents of the array.

Your first example doesn't define main, it just declares it, hence the linker error.

The second example defines main, but incorrectly.

Richard Pennington
> The second example defines main, but incorrectly.Does this mean compiler allocates some storage for this code? `void (*main)();`Is this not just a declaration, main points to a function that takes an unspecified number of arguments and returns nothing? (as opposed to a definition)?
Gowtham
+1 for the post. Can you give example of main declared as an array and the code will work? I am quite curious to know this. Have never come across such a code.
Jay
In the olden days, it was easier to do stuff like that. For an example of an executable array see http://stackoverflow.com/questions/2251859/cant-find-my-syntax-error-vc-says-theres-one/2251892#2251892
Richard Pennington
`int main[] = { 0xC3 };`0x63 is the opcode for RET (return). Surprisingly, this seems to return 1! Not sure where this 1 comes from. ;)
Gowtham
+2  A: 

You declared a pointer-to-function named main, and the linker warned you that this wouldn't work.

The _WinMain message has to do with how Windows programs work. Below the level of the C runtime, a Windows executable has a WinMain.

bmargulies
A: 

In listing 1, you are saying "There's a main() defined elsewhere in my code --- I promise!". Which is why it compiles. But you are lying there, which is why the link fails. The reason you get the missing WinMain16 error, is because the standard libraries (for Microsoft compiler) contain a definition for main(), which calls WinMain(). In a Win32 program, you'd define WinMain() and the linker would use the library version of main() to call WinMain().

In Listing 2, you have a symbol called main defined, so both the compiler & the linker are happy, but the startup code will try to call the function that's at location "main", and discover that there's really not a function there, and crash.

James Curran
Does this mean compiler allocates some storage for this code? `void (*main)();` Is this not just a declaration, main points to a function that takes an unspecified number of arguments and returns nothing? (as opposed to a definition)?
Gowtham
No. it allocate space for a *pointer* to a function that takes an unspecified number of arguments and returns nothing. `char* main;` or even `void *main;` would have accomplished the same thing.
James Curran
A: 

1.) An (compiler/platform) dependent function is called before code in main is executed and hence your behavior(_init in case of linux/glibc).
2) The code crash in 2nd case is justified as the system is unable to access the contents of the symbol main as a function which actually is a function pointer pointing to arbitrary location.

xyz
+1  A: 

On Windows platforms the program's main unit is WinMain if you don't set the program up as a console app. The "@16" means it is expecting 16 bytes of parameters. So the linker would be quite happy with you as long as you give it a function named WinMain with 16 bytes of parameters.

If you wanted a console app, this is your indication that you messed something up.

T.E.D.