I ask because my compiler seems to think so, even though I don’t.
echo 'int main;' | cc -x c - -Wall
echo 'int main;' | c++ -x c++ - -Wall
Clang issues no warning or error with this, and gcc issues only the meek warning: 'main' is usually a function [-Wmain]
, but only when compiled as C. Specifying a -std=
doesn’t seem to matter.
Otherwise, it compiles and links fine. But on execution, it terminates immediately with SIGBUS
(for me).
Reading through the (excellent) answers at What should main() return in C and C++? and a quick grep through the language specs, it would certainly seem to me that a main function is required. But the verbiage from gcc’s -Wmain
(‘main’ is usually a function) (and the dearth of errors here) seems to possibly suggest otherwise.
But why? Is there some strange edge-case or “historical” use for this? Anyone know what gives?
My point, I suppose, is that I really think this should be an error in a hosted environment, eh?
Since the question is double-tagged as C and C++, the reasoning for C++ and C would be different:
- C++ uses name mangling to help linker distinguish between textually identical symbols of different types, e.g. a global variable
xyz
and a free-standing global functionxyz(int)
. However, the namemain
is never mangled. - C does not use mangling, so it is possible for a program to confuse linker by providing a symbol of one kind in place of a different symbol, and have the program successfully link.
That is what's going on here: the linker expects to find symbol main
, and it does. It "wires" that symbol as if it were a function, because it does not know any better. The portion of runtime library that passes control to main
asks linker for main
, so linker gives it symbol main
, letting the link phase to complete. Of course this fails at runtime, because main
is not a function.
Here is another illustration of the same issue:
file x.c:
#include <stdio.h>
int foo(); // <<== main() expects this
int main(){
printf("%p\n", (void*)&foo);
return 0;
}
file y.c:
int foo; // <<== external definition supplies a symbol of a wrong kind
compiling:
gcc x.c y.c
This compiles, and it would probably run, but it's undefined behavior, because the type of the symbol promised to the compiler is different from the actual symbol supplied to the linker.
As far as the warning goes, I think it is reasonable: C lets you build libraries that have no main
function, so the compiler frees up the name main
for other uses if you need to define a variable main
for some unknown reason.
main
isn't a reserved word it's just a predefined identifier (like cin
, endl
, npos
...), so you could declare a variable called main
, initialize it and then print out its value.
Of course:
- the warning is useful since this is quite error prone;
- you can have a source file without the
main()
function (libraries).
EDIT
Some references:
main
is not a reserved word (C++11):The function
main
shall not be used within a program. The linkage (3.5) ofmain
is implementation-defined. A program that defines main as deleted or that declares main to beinline
,static
, orconstexpr
is ill-formed. The namemain
is not otherwise reserved. [ Example: member functions, classes and enumerations can be calledmain
, as can entities in other namespaces. — end example ]C++11 - [basic.start.main] 3.6.1.3
[2.11/3] [...] some identifiers are reserved for use by C++ implementations and standard libraries (17.6.4.3.2) and shall not be used otherwise; no diagnostic is required.
[17.6.4.3.2/1] Certain sets of names and function signatures are always reserved to the implementation:
- Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter (2.12) is reserved to the implementation for any use.
- Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
Reserved words in programming languages.
Reserved words may not be redefined by the programmer, but predefineds can often be overridden in some capacity. This is the case of
main
: there are scopes in which a declaration using that identifier redefines its meaning.
Is int main;
a valid C/C++ program?
It is not entirely clear what a C/C++ program is.
Is int main;
a valid C program?
Yes. A freestanding implementation is allowed to accept such program. main
doesn't have to have any special meaning in a freestanding environment.
It is not valid in a hosted environment.
Is int main;
a valid C++ program?
Ditto.
Why does it crash?
The program doesn't have to make sense in your environment. In a freestanding environment the program startup and termination, and the meaning of main
, are implementation-defined.
Why does the compiler warn me?
The compiler may warn you about whatever it pleases, as long as it doesn't reject conforming programs. On the other hand, warning is all that's required to diagnose a non-conforming program. Since this translation unit cannot be a part of a valid hosted program, a diagnostic message is justified.
Is gcc
a freestanding environment, or is it a hosted environment?
Yes.
gcc
documents the -ffreestanding
compilation flag. Add it, and the warning goes away. You may want to use it when building e.g. kernels or firmware.
g++
doesn't document such flag. Supplying it seems to have no effect on this program. It is probably safe to assume that the environment provided by g++ is hosted. Absence of diagnostic in this case is a bug.
It is a warning as it is not technically disallowed. The startup code will use the symbol location of "main" and jump to it with the three standard arguments (argc, argv and envp). It does not, and at link time cannot check that it's actually a function, nor even that it has those arguments. This is also why int main(int argc, char **argv) works - the compiler doesn't know about the envp argument and it just happens not to be used, and it is caller-cleanup.
As a joke, you could do something like
int main = 0xCBCBCBCB;
on an x86 machine and, ignoring warnings and similar stuff, it will not just compile but actually work too.
Somebody used a technique similar to this to write an executable (sort of) that runs on multiple architectures directly - http://phrack.org/issues/57/17.html#article . It was also used to win the IOCCC - http://www.ioccc.org/1984/mullender/mullender.c .
Is it a valid program?
No.
It is not a program as it has no executable parts.
Is it valid to compile?
Yes.
Can it be used with a valid program?
Yes.
Not all compiled code is required to be executable to be valid. Examples are static and dynamic libraries.
You have effectively built an object file. It is not a valid executable, however another program could link to the object main
in the resultant file by loading it at runtime.
Should this be an error?
Traditionally, C++ allows the user to do things that may be seem like they have no valid use but that fit with the syntax of the language.
I mean that sure, this could be reclassified as an error, but why? What purpose would that serve that the warning does not?
So long as there is a theoretical possibility of this functionality being used in actual code, it is very unlikely that having a non-function object called main
would result in an error according to the language.
I would like to add to the answers already given by citing the actual language standards.
Is ‘int main;’ a valid C program?
Short answer (my opinion): only if your implementation uses a "freestanding execution environment".
All following quotes from C11
5. Environment
An implementation translates C source files and executes C programs in two dataprocessing-system environments, which will be called the translation environment and the execution environment [...]
5.1.2 Execution environments
Two execution environments are defined: freestanding and hosted. In both cases, program startup occurs when a designated C function is called by the execution environment.
5.1.2.1 Freestanding environment
In a freestanding environment (in which C program execution may take place without any benefit of an operating system), the name and type of the function called at program startup are implementation-defined.
5.1.2.2 Hosted environment
A hosted environment need not be provided, but shall conform to the following specifications if present.
5.1.2.2.1 Program startup
The function called at program startup is named main. [...] It shall be defined with a return type of int and with no parameters [...] or with two parameters [...] or equivalent or in some other implementation-defined manner.
From these, the following is observed:
- A C11 program can have a freestanding or a hosted execution environment and be valid.
- If it has a freestanding one, there need not exist a main function.
- Otherwise, there must be one with a return vale of type int.
In a freestanding execution environment, I would argue that it is a valid program that does not allow startup to happen, because there is no function present for that as required in 5.1.2. In a hosted execution environment, while your code introduces an object named main, it cannot provide a return value, so I would argue that it is not a valid program in this sense, although one could also argue like before that if the program is not meant to be executed (on might want to provide data only for example), then it just does not allow to do just that.
Is ‘int main;’ a valid C++ program?
Short answer (my opinion): only if your implementation uses a "freestanding execution environment".
Quote from C++14
3.6.1 Main function
A program shall contain a global function called main, which is the designated start of the program. It is implementation-defined whether a program in a freestanding environment is required to define a main function. [...] It shall have a return type of type int, but otherwise its type is implementation-defined. [...] The name main is not otherwise reserved.
Here, as opposed to the C11 standard, less restrictions apply to the freestanding execution environment, as no startup function is mentioned at all, while for a hosted execution environment, the case is pretty much the same as for C11.
Again, I would argue that for the hosted case, your code is not a valid C++14 program, but I am sure that it is for the freestanding case.
Since my answer only considers the execution environment, I think the answer by dasblinkenlicht comes into play, as name mangling occuring in the translation environment happens beforehand. Here, I am not so sure that the quotes above are observed so strictly.
My point, I suppose, is that I really think this should be an error in a hosted environment, eh?
The error is yours. You didn't specify a function named main
that returns an int
and tried to use your program in a hosted environment.
Suppose you have a compilation unit that defines a global variable named main
. This might well be legal in a freestanding environment because what constitutes a program is left up to the implementation in freestanding environments.
Suppose you have another compilation unit that defines a global function named main
that returns an int
and takes no arguments. This is exactly what a program in a hosted environment needs.
Everything's fine if you only use the first compilation unit in a freestanding environment and only use the second in a hosted environment. What if you use both in one program? In C++, you've violated the one definition rule. That is undefined behavior. In C, you've violated the rule that dictates that all references to a single symbol must be consistent; if they aren't it's undefined behavior. Undefined behavior is a "get out of jail, free!" card to developers of an implementation. Anything an implementation does in response to undefined behavior is compliant with the standard. The implementation doesn't have to warn about, let alone detect, undefined behavior.
What if you use only one of those compilation units, but you use the wrong one (which is what you did)? In C, the situation is clear-cut. Failure to define the function main
in one of the two standard forms in a hosted environment is undefined behavior. Suppose you didn't define main
at all. The compiler/linker doesn't haven't to say a thing about this error. That they do complain is a nicety on their behalf. That the C program compiled and linked without error is your fault, not the compiler's.
It's a bit less clear in C++ because failure to define the function main
in a hosted environment is an error rather than undefined behavior (in other words, it must be diagnosed). However, the one definition rule in C++ means linkers can be rather dumb. The linker's job is resolving external references, and thanks to the one definition rule, the linker doesn't have to know what those symbols mean. You provided a symbol named main
, the linker is expecting to see a symbol named main
, so all is good as far as the linker is concerned.
For C so far it is implementation defined behavior.
As the ISO/IEC9899 says:
5.1.2.2.1 Program startup
1 The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent; or in some other implementation-defined manner.
No, this is not a valid program.
For C++ this was recently explicitly made ill-formed by defect report 1886: Language linkage for main() which says:
There does not appear to be any restriction on giving main() an explicit language linkage, but it should probably be either ill-formed or conditionally-supported.
and part of the resolution included the following change:
A program that declares a variable main at global scope or that declares the name main with C language linkage (in any namespace) is ill-formed.
We can find this wording in the latest C++ draft standard N4527 which is the the C++1z draft.
The latest versions of both clang and gcc now make this an error (see it live):
error: main cannot be declared as global variable
int main;
^
Before this defect report, it was undefined behavior which does not require a diagnostic. On the other hand ill-formed code requires a diagnostic, the compiler can either make this a warning or an error.
来源:https://stackoverflow.com/questions/27777071/is-int-main-a-valid-c-c-program