Why do we need the main function and can't we execute the code without it? Can't we just execute our code outside the main function by making our own function?
7 Answers
Well, there needs to be somewhere your code starts executing(apart from the necessary initialisation and cleanup, which isn't readily visible to the programmer in the form of code).
Let's take reference to the C language, which influenced almost every other programming language. Documentation for main()
in C states
Every C program coded to run in a hosted execution environment contains the definition (not the prototype) of a function named main, which is the designated start of the program.
The main function is called at program startup, after all objects with static storage duration are initialized. It is the designated entry point to a program that is executed in a hosted environment (that is, with an operating system).
Now if we are talking about assembly language, here is what an assembly code would look like
org 0x100
mov dx, msg
mov ah, 9
int 0x21
mov ah, 0x4c
int 0x21
msg db 'Where is my main() here?', 0x0d, 0x0a, '$'
And now python
print("No main!")
As you can see, main()
isn't mandated, it's rather a specification and a convention which has been followed all along for the languages that do mention it(likes of C, C++, Java), and well, it does serve a purpose. And yes, you can have a program that doesn't start from main()
, at least in C to my knowledge(gcc
via nostartfiles
option).
-
2$\begingroup$ Note that the standard specifically says
main
is not a function, it is an entry point. I.e., you aren't allowed to callmain
. Yes, most Unixy C implementatons call amain
function to way any function is called, but there might be (probably are) ones that don't. $\endgroup$– vonbrandCommented May 6, 2023 at 18:14 -
$\begingroup$ That's 16-bit x86 code for a DOS
.com
executable. In executable file formats with metadata (like DOS/Windows PE.exe
), you typically would define a symbol in the asm source, perhapsWinMain@16
. Or under Linux, like you say withgcc -nostartfiles
, you'd define a_start:
label as the actual ELF entry point, instead of linking in the CRT startup code which provides a_start
that (indirectly) callsmain
. $\endgroup$ Commented May 6, 2023 at 20:19 -
8$\begingroup$ @vonbrand: You're mixing up C and C++. In C,
main
is a function you're allowed to call from elsewhere in the program. (calling main() in main() in c). In C++ it's not, letting the compiler put constructor hooks at the top ofmain
instead of in code that runs beforemain
. (Cygwin or MinGW gcc actually does this for some reason.) $\endgroup$ Commented May 6, 2023 at 20:21 -
1$\begingroup$ In Java (simplifying slightly), every class can have a main() method and you have to say which one you want to execute, by naming the class either on the command line itself or by establishing a default entry point in the JAR file manifest. $\endgroup$ Commented May 8, 2023 at 6:46
-
1$\begingroup$ As for the last part of this answer, as an embedded developer I've often written perfectly valid freestanding C code without a
main()
, where according to the C standard "the name and type of the function called at program startup are implementation-defined." $\endgroup$– pipeCommented May 8, 2023 at 10:12
This is a design decision in the C language. Besides making main
a reserved name, this is quite harmless and you can always implement the main function as a mere call to your favorite function. Also note that main
has a fixed prototype, that allows to interact with the OS.
Without this convention, you would need to tell the linker what is the entry point in the executable by some external method or a special C declaration.
Other languages have different conventions. For instance Pascal and FORTRAN demand a Program declaration. Python works like an implicit function at file level.
-
2$\begingroup$
main
isn't usually the OS-level entry point. On GNU/Linux systems, the ELF entry point is normally called_start
, which passes the address ofmain
to__libc_start_main
(in libc.so.6), which inits library data structures then calls that function pointer. That_start
code comes fromcrt1.o
etc. which compilers also link in to each executable. If you were writing by hand in assembly, with your own entry point code, that's when you'd useld -e my_entry_point -o foo foo.o
if you didn't want to name it_start
. $\endgroup$ Commented May 6, 2023 at 20:12 -
2$\begingroup$ If you use
gcc -c hello.c
/ld -e main hello.o
, you won't get a working executable (even if you link-lc
). See also What is the use of _start() in C? / ld : _start not found defaulting to , and Assembling 32-bit binaries on a 64-bit system (GNU toolchain) for some x86 Linuxmain
vs._start
stuff. $\endgroup$ Commented May 6, 2023 at 20:14 -
$\begingroup$ @PeterCordes: it's the job of the C compiler to tie the
main
function to the proper entry point, whatever it is (plus the handling of theargc
/argv
arguments). $\endgroup$– user16034Commented May 6, 2023 at 20:17 -
2$\begingroup$ Correct. And as you say, the CRT startup code also handles the difference between the process startup environment (e.g. in the System V ABI with the stack pointer initially pointing at
argc
thenargv[0..n]
values in stack memory) vs. the function calling convention. (Args in registers, or on the stack with a return address below them, something the ELF entry point doesn't have.) $\endgroup$ Commented May 6, 2023 at 20:25 -
1$\begingroup$ @AyxanHaqverdili: main is technically not a reserved identifier. I don't want to clutter my answer with such details, this is CS. Though the habit originated in the C language, the answer is not limited to that one. Next time I'll put quotes around. $\endgroup$– user16034Commented May 8, 2023 at 7:17
This is partly to do with the grammatical structure of the language. Consider Java for example:
- At the top level, each file is a compilation unit,
- A compilation unit contains type declarations (classes, interfaces or enums),
- A type declaration contains member declarations (fields, methods, constructors...),
- A method or constructor declaration contains statements.
Ultimately, statements are what get executed. The language's grammar is simpler by not having extra rules to allow statements at the top level, only declarations. The semantics of the language are also simpler when you consider programs whose declarations span multiple files, since there is no need to define what order statements at the top levels of different files should be executed in. The implementation is also potentially simpler because declarations don't need to be ordered.
Other languages such as Python allow statements at the top level because all declarations (e.g. def
or class
) are a kind of statement ─ in such languages, even import
is a statement that is executed, so the order of execution of top-level statements in multiple files is determined by the order of import
statements in the files which import them. This tends to be the case for more dynamic languages, which will load modules and resolve names to declarations at runtime, so that there is no need for the compiler to find all of the declarations before it compiles statements, because the compiler doesn't need to know the meanings of the names which occur in those statements.
-
$\begingroup$ Comments have been moved to chat; please do not continue the discussion here. Before posting a comment below this one, please review the purposes of comments. Comments that do not request clarification or suggest improvements usually belong as an answer, on Computer Science Meta, or in Computer Science Chat. Comments continuing discussion may be removed. $\endgroup$– D.W. ♦Commented May 8, 2023 at 7:31
An important philosophical point you might want to consider: Is there really a fundamental difference between declaring a place where the program starts, and simply having the program start at the top of a specific file? main
, in all the languages that have such a thing, is really just a marker that says "start here." Some languages have a main
marker, and some appear not to, but really, for those languages that don't seem to have a declared main
, they still have a place to start — it's just implicitly chosen!
So another way to look at this thought experiment: In languages like C# and Pascal we might explicitly write main()
to tell the program where to begin. But is that really truly different from the compiler invisibly inserting main() {
at the start of the file and }
at the end if we didn't write such a thing ourselves? Looked at this way, there's always a main()
— but you just may not have written it yourself.
So that's the real difference:
- Some languages require you to say where the program begins. (C, C++, Pascal, Java, Rust.)
- Some languages allow you to say where the program begins, and they have a rule for where it begins if you don't explicitly state otherwise. (Modern C#.)
- Some languages only have a rule for where the program begins, and it always begins there. (JavaScript, Python, Ruby, Lisp.)
The program always starts somewhere. The only real question is whether your language lets you or forces you to choose that somewhere, or whether it chooses that somewhere by itself.
(Addendum, just for completeness: There's also another category in the bullet points above for declarative languages like SQL and Prolog, where there's really no main
at all: The language implementation decides what order to run the pieces of your program in, and whether A is run before B is really up to the computer. Then there's arguably also a category for languages like HTML and CSS and SVG, where it's arguably still a "program," but how it even runs at all doesn't matter as long as the output is correct. There are lots of ways to describe a program, and lots of different ways to have or not have a main
; one size does not even come remotely close to fitting all!)
-
$\begingroup$ This is all true (+1), although I think it is worth making the point that your third category of languages, where the program begins executing "at the start of the source file", are all languages where the source files exist at runtime and the program is invoked by executing a particular source file. Therefore this design isn't really an option when a language is compiled and linked from multiple source files into one binary ─ you would still need to explicitly declare which source file is the entry point, at least. $\endgroup$– kaya3Commented May 8, 2023 at 17:20
-
$\begingroup$ @kaya3 There are plenty of oddball categories out there, like assembly ROM code that starts at a fixed address, or Smalltalk and Lisp environments that never truly shut down; but once you get the idea that
main
is just a way to tell the machine where your program begins, you can usually come up with all sorts of clever answers about ways that could be made to work. $\endgroup$ Commented May 8, 2023 at 18:06
An application or program has a start. That's the "main" function. Many languages do not call it "main", and in many it is implicit (e.g. the function defined by the script as a whole).
On the other hand, libraries are collection of functions (and code, data, resources, etc.), and do not have a starting point. You chose your own "starting point" every time you call it. (Some libraries have initialization, and some have state.)
Why do we need the main function and can't we execute the code without it?
It depends entirely on how the language is defined. Programming languages are man-made constructs anyway, so we can make them as we like. With that in mind, we don't "need" a main function, and we can well have a language that can read from outside any function.
Now, I'm not sure if you wanted discount them for some reason, but many interpreted "scripting" languages, like e.g. Perl, Python, and the various shell languages are good examples of languages where the tooling is happy with code in the top level, outside functions. But for non-trivial programs, it's often useful for us humans to structure the code using functions, including a main function (even if you have to call it explicitly.) Since larger programs will use functions anyway, and for smaller programs, it's only an extra few lines of boilerplate, it's not a big leap for a language designer to choose that all code must reside in functions. It might make the language syntax slightly more straightforward to define, too.
A lot of great answers have already been given, but I would like to name some additional aspects I find quite important as well: not having to define a main function as the entry point encourages less encapsulation and thus less clean, in general uglier (and sometimes also even unusable) code.
This is because high indentation levels are almost always regarded as something you should seek to avoid, and thus code that should have been separated among different classes, methods, functions or even modules is just sequentially written down in languages that support it. In addition, it prevents that callers need to execute arbitrary code at runtime when importing modules - there is a reason why idioms like if __name__ == "__main__"
are always recommended, even in smaller projects, in languages like Python.
main
. They just execute everything given to them. Python is also like that. $\endgroup$__main__
is an environment, not a function. And also, stuff that is defined in class definitions is executed. Actually, everything is just exectuted. $\endgroup$main
) or it can be whatever you like. Those are different conventions and different languages use different conventions. $\endgroup$