main() function prototypes

As far as I know,

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>main ()
</code>
<code>main () </code>
main ()

function has the following prototypes:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code> int main();
int main(int argc, char **argv);
</code>
<code> int main(); int main(int argc, char **argv); </code>
    int main();
    int main(int argc, char **argv);

Now, C does not support overloading, then how are multiple prototypes of

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code> main ()
</code>
<code> main () </code>
    main ()

supported?

4

As a program can only contain one function called main, it is actually very simple for the compiler to support the multiple signatures.

In the call-sequence for main, the caller is made responsible for cleaning up any arguments that were provided.
And the compiler provides a piece of startup code that prepares the arguments for main and then invokes the one function of that name, without checking if it will actually use those arguments.


As a side note, the last two prototypes are identical and in a function definition, the first two would be identical as well. That leaves only two supported signatures for main.

3

One thing you have to understand about C or any other language that produces native object files is that the only time function prototypes matter is during compilation. By the time the linker sees it, the only thing to be done is fill in the missing addresses of external functions.

Arranging the passing of function parameters is entirely up to the compilers, usually based on an architecture-specific convention. Most implementations on machines with stacks push the parameters in reverse order followed by the return address. Ergo, when code wants to call f(int a1, int a2, int a3), the stack would contain Return Address a1 a2 a3 if you were reading it from the top down. This means the function can get at a1 by looking at the second item in the stack, a2 by looking at the third, etc.

Calling main() works exactly the same way, so from its perspective, the stack will contain Return Address argc argv envp. (That last item is something Unix and other systems have done for decades, but it’s not in any standard. You’ll see why this doesn’t matter in a second.)

Section 5.1.2.2.1 of the C standard specifically says that no implementation will define a prototype for main() and that the two standard implementations are main() and main(int argc, char **argv). Not having a pre-defined prototype allows you to declare main any way you like and not have the compiler balk at it. A zero-argument version will ignore the stack entirely and the two-argument flavor will look at the second and third items. You could also, do a one-argument version, main(int argc), which would work because it would consume argc and not know that argv is there.

As you might have guessed, this trick only works in the direction of a caller calling a function with more arguments than the called function consumes will just have pushed on more than the caller will see. A called function with more parameters than the caller pushed will simply look further down the stack than it should and fall victim to the GIGO principle. Since the caller undoes the adjustment to the stack pointer, the stack comes out of it unscathed after the called function returns.


Addendum, addressing Bart van Ingen Schenau’s comment:

C++ mangles its symbol names to prevent collisions between same-named, differently-prototyped functions, as almost every native object file format on the planet differentiates symbols only by name. That has the pleasant side effect of preventing mismatched calls between C++ object files, but only because a C++ compiler compiling a wrongly-prototyped call will emit a symbol that won’t be present in the object file that would contain the called function. It happens that you get human-readable C++ function names in linker error messages because many of them recognize and demangle C++ symbols.

An object file can refer to a C++ function in another object file by its mangled name and attempt to call it. (I’ve actually done this experimentally and would never in a million years condone doing it in “real” code.) The linker, which has no idea whether either object was produced by a C++ compiler or from some bit of hand-written assembly, will do nothing to prevent it as long as the symbol names match. That makes the assertion that the linker plays any direct role in enforcing C++ language policies erroneous.

3

If you define a function named foo, you can give it any (legal) prototype you like:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>int foo(void);
int foo(int argc, char *argv[]);
void foo(long double this, const unsigned short ***that, struct thingie the_other);
</code>
<code>int foo(void); int foo(int argc, char *argv[]); void foo(long double this, const unsigned short ***that, struct thingie the_other); </code>
int foo(void);
int foo(int argc, char *argv[]);
void foo(long double this, const unsigned short ***that, struct thingie the_other);

You’re defining foo yourself, so you can define it any way you like.

Similarly, you’re defining main yourself; the implementation doesn’t define it for you. What’s different about main is not that it can have one of two different prototypes, it’s that it’s restricted to have one of only those two different prototypes (or equivalent). And that’s to ensure that the compiler and the calling environment know how to invoke your main function. (For foo, any calls will be your own.)

(main may also be defined in some other implementation-defined form, but such forms are not portable.)

As for why those two are permitted, rather than, say, requiring exactly the second form, it’s mostly for historical reasons. Early C compilers didn’t have prototypes (they were introduced in the 1989 C standard, borrowed from C++). In pre-standard C, defining

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>main() { /* ... */ }
</code>
<code>main() { /* ... */ } </code>
main() { /* ... */ }

probably just meant that the calling environment would pass argc and argv values (and possibly envp) to main, and main would simply ignore them. It was convenient to omit the definitions of argc and argv if your program wasn’t going to use them. Calling conventions were such that the two forms were effectively compatible.

For historical reasons, modern calling conventions are likely to work similarly, but since the 1989 ANSI standard compilers have been permitted to make the two forms incompatible — but if they are, then the implementation has to do whatever is necessary to make both forms work.

C does not support overloading

C does support overloading, it doesn’t support user defined overloading of functions but operators have a fixed set of standard defined overloads.

how are multiple prototypes of main () supported?

The compiler has to do the right things for different possible definitions of main(), but it has just to keep one prototype for recurse call checks; it hasn’t to behave differently for main than for any other function excepted when compiling its definition. You can’t provide yourself a prototype which won’t match the definition you use and expect things behave sanely.

BTW, note that has your two last lines are strictly equivalent and the difference between the two first may occurs in valid programs for other functions than main.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật