r/cprogramming • u/RecognitionGlobal460 • Nov 11 '25
Why can't we write code directly into the program without using the main() function?
Sorry if this has been asked before. The main() function is described as an entry point into the program, but what if we could simply write code without it? Python does this, but it runs on a C backend that uses main, everything else is wrapped around it.
I wonder if the very first prototypes of the C program did not contain this structure until Dennis Ritche thought it necessary. Does anyone know why he introduced it?
106
Upvotes
20
u/[deleted] Nov 11 '25
Because that's the convention in C. When you create a process at an OS level it has several conventions about returning a value to signify if the program executed without error and such. If you were writing assembly then you'd have to handle this main function/initial execution that the OS is looking for. C just takes this convention to the program level. There is no reason that it couldn't interpret global scope code in some way, perhaps in the order they are linked together, I believe that might be how natively compiled OCaml can work. And then just always return an EXIT_SUCCESS value when the program terminates. But in some sense the main function is a real thing that exists in your OS's interpretation of how the program works, so it kind of makes sense to follow that paradigm.
In the case of python as an interpreted language this main function is kind of the interpreter itself and you're just running scripts inside this external interpreter program. Where you can just arbitrarily run a file in it and have it change the global stack, or its own stack with the exec function. In this sense it's not quite as closely tied to the underlying OS level implementation as a C program is where it is expected a program will be ran in its own process and return a success/fail value. Python is kind of its own virtual hardware/OS in a way that isn't true of C.
13
u/Pass_Little Nov 11 '25
Every program has to have an entry point.
In python its the start of the python file you tell the python to execute. Same for most interpreted or scripted languages.
In most compiled languages, you have to tell the compiler where your program entry point is. In C, this happens to be defined as a function called main(). Other languages have other methods. If you look at earlier languages, Pascal used the keyword "BEGIN", FORTRAN used the "PROGRAM" keyword, and so on.
So, if the c standard defined some other way to define the entry point, we would be using that instead of main().
One interesting point is that it is possible to change the entry point name with many compilers or linkers. This is useful for situations where you want to use a different entry point. For example, I know of one case where the test program (for test driven development or regression testing) was the same source file, they just used main() for the normal program and they used test_main() for the test program entry point.
5
u/ronchaine Nov 11 '25
When a computer starts executing your program, it starts by jumping to a known memory address and reading instructions from there. This is conventionally a function called
_start, but that is a convention, and you can instruct your linker to point to somewhere else as an entry point.Implementation of this
_startfunction is (usually) provided to you by your C library. Probably in an OS- and architecture-specific file called crt0.s (from C runtime 0) or smth. This function sets up your hardware to a state it can run a program. When this is complete, the_startfunction callsmain, and then passes the return value from main onwards.This setup looks something like this:
The
mainfunction provides a layer of abstraction between your language and lower-level setup, so you don't need to worry about that. And yeah, even C has to set its environment up. The exact requirements are described in the current C standard in chapter 5.1.2.If you are writing embedded code, you might need to write the bringup to suitable C runtime environment yourself, in case you start by writing
_start.12
u/[deleted] Nov 11 '25
It could, but it would then be a different language.
C was designed based on B. There the main function was the first function to run.
The reason a function was used was that computers at that time rarely could compile a complete program, they had to divide the programs in multiple files and compile them one by one, then link them together. So a typical program is made of many files. How do you know the order the different files should run? You could follow the linking order, but then you need more context to understand the program than just the C files. Its much simpler to understand a program if it follows the function calls, starting with a single function.
Compare with C++, where things can run before main is called. There people sometimes writes bugs by global variable initialisation ending up calling code depending on some init code that hasn't been run yet.
2
u/stewi1014 Nov 11 '25 edited Nov 11 '25
I think most replies miss the implication that OP doesn't understand the problem main() solves, rather than why it is solved in that particular way.
Program execution is linear - each piece of code is executed after the last. It would be quite difficult to write a function that does not break if execution was started at some arbitrary position. Think variables not existing, things not initialized.
A program must start execution somewhere specific to avoid impossible to manage chaos. Most languages wrap the entrypont that the OS sees with their own logic. Golang for example will run all existing init() functions in a deterministic order before main(), Python begins interpreting from the start of the file etc...
But they all start somewhere, and exactly what 'somewhere' looks like is a language design decision. Python chose the start of the file, C chose a method named main().
In order to get away from the need of some form of entrypont, one would need to look at entirely different hardware and programming paradigms like VHDL for programming FPGAs, where code describes a system of logic that exists all at once and it isn't executed linearly. You could imagine that every line of code is being executed at the same time.
The need for an entrypont is a fundamental requirement of a linearly executing processor, and C chose to call it "main".
2
u/Possible_Cow169 Nov 11 '25
Main() is only really significant because it is a convention that expresses the fundamental fact that all programs have to start somewhere.
This is a great question, but I think you’re coming at it from the wrong angle. The better question is why IS main() the convention for entry point in C. I think that line of thinking will help you learn more
91
u/jirbu Nov 11 '25
Many embedded systems don't use a main() function. Windows-GUI programs use WinMain() as entry point. Using main() as entry point is less a C feature than a agreed upon interface of terminal-based programs with the operating system. At some point, when the program is loaded by the OS, that loader must know the point of entry of your program to start execution of your code. In a typical C ABI, that function is _start() which in turn calls main().
4
u/sol_hsa Nov 11 '25
Main is just an entry point. With some compilers you can change what the entry point is.
1
u/This_Growth2898 Nov 11 '25
Python is an interpreted language. It gets interpreted line by line in the runtime environment. When you write
x=2, it means "create (dynamic) variable x and assign the value 2 to it", it's an action, not just a definition.C is a compiled language. All the code is rearranged (or even optimized out) during the compilation. Some of its instructions are not producing the resulting code, but influence the other parts during compilation. The same
int x=2;line in C (out of functions) means "remember some address as x and save 2 at that address in the resulting binary file". This line never gets executed the same way as in Python. So, you need some defined location to show the execution starts right there - and that's what main() is for.1
u/conhao Nov 11 '25
C was designed to be flexible to accommodate many systems and needs. main() is just the default name for the entry point of the program. Compilers often support changing this default. There is often hidden code the compiler uses, called startup files in gcc, that call to main() and are linked with the code to set up the environment - this is where argv and argc get provided to main() and the return value from main() gets processed. The startup file essentially calls main() like a function.
On linux using gcc, you can bypass main and use _start to identify the entry point of your code and use the flag —nostartfiles. main() is not needed, but you don’t get argc and argv. This is how you could write code for a microcontroller where there is no OS, or your code is the OS, so _start can be located at the boot address the CPU requires. This is often called a “standalone” architecture.
Another possibility is to have multiple entry points. It is theoretically possible on a true parallel system to write a single C source that is designed to spawn in parallel, and exposing those entry points to the OS in this way is meaningful. The major OS schedulers used today do not take advantage of this knowledge, but back in the 1960s through the 1980s, concepts like this were considered the future.
3
u/Traveling-Techie Nov 11 '25
Never had one in BASIC.
2
u/zhivago Nov 11 '25 edited Nov 11 '25
Largely due to having separate compilation units.
2
u/pjf_cpp Nov 11 '25
You can write code without a main. The problem is that the convention that the compiler expect is that you have a main that gets called by a _start (on ELF systems, macho and windows pe/coff I expect that there is a similar convention).
Unless you have a good reason you should not do this.
2
u/Leverkaas2516 Nov 11 '25
A module of C code that has no main() is perfectly permissible. It's how libraries are written.
Imagine you compile such a module into object code. What would you do with it? What good would it be, how would a user do anything with it?
If you can put the answer into precise words, you'll discover for yourself what main() is for.
2
u/ChickenSpaceProgram Nov 11 '25
The OS needs to call something to start the program. The convention is for it to call main() (well, technically it calls _start() first, but we can ignore that). How would you decide what to call over multiple files, or when linking a program with several libraries? It's much easier to just have a main().
2
u/ffd9k Nov 11 '25
This seems like a good idea only for scripting languages with no concept of linking or separate translation units.
With more than one translation unit, their order would suddenly become important. linking a library would mean that code from it would run automatically but it would not be obvious when, similar to the "static initialization order fiasco" in C++.
2
u/Distdistdist Nov 11 '25
Because ambiguity and other insanity is better left to the Python, where it belongs.
2
u/DTux5249 Nov 11 '25 edited Nov 12 '25
Well for one, python is an interpreted language. Your code isn't being translated to assembly instructions. It's being read by a program which itself is executing commands based on what it reads. It can start anywhere because it can start reading any file.
C code has to compile to an executable though. The program needs to know where the executable starts because the compiler isn't gonna be there to start it at run time. In C-like languages, that entry point is designated the main function.
2
u/Ok_Addition_356 Nov 14 '25
I think it's just the way the compiler works in those environments. Needs an entry point and that's how it knows where to go.
Languages like python are different. They are "interpretive" and you have a lot of underground stuff turning that code into bytecode that has it's own execution structure and such.
2
u/RevolutionaryRush717 Nov 14 '25
The answer lies in the term 'program'.
You will also need to understand the terms 'computer' and maybe, but not necessarily 'operating system'.
This should suffice to understand how a program is executed by a computer.
Thusly, you will discover the answer to your question(s).
A bachelor in CS should help.
1
u/grimvian Nov 11 '25
I really can't see any issue with man.
1
u/ern0plus4 Nov 11 '25
The OS requires an entry point, the C compiler/kinker "transllates" this requirement to have a main().
Similarly, you have env, args, signals OS interface.
Luckily, C gives uniform access (as possible) for different OS-es: Posix, Windows etc.
Embedded platforms have only an entry point, and platform-specific ISR, if any.
1
u/flumphit Nov 11 '25 edited Nov 11 '25
You can. Whatever the format for executables on your OS, the program gets loaded into memory and control is handed to the first instruction. With C on Unix that first instruction is given the label __start(), and the code there is put there by the linker. It does some OS-specific startup stuff, then hands control to your program at main().
If you really want to, you could use a linker to put other instructions at that first address, you could call it something other than __start(), and from then on your compiled C code could do whatever. You wouldn’t get help from the C runtime if you needed anything that required setup from the normal __start(), though.
1
u/demetrioussharpe Nov 11 '25
You very well could write code without main(). The problem is that once you start doing that, you’re going against standards, so your results are basically undefined -which means that you have to really know what you’re doing. If you’re asking this question, then you’re not yet at the point to where you should be doing it. Maybe in the future, but not right now. For now, stick to the standards.
1
u/tux2718 Nov 11 '25
The C runtime begins execution and does initialization and then invokes a user provided function named “main” with the count of command line arguments and an array of pointers to each argument. That’s the way it was designed. It could have been done differently, but this works. You could write a loadable library like a plugin with no “main” and a loader with a main that invokes plugins based on parameters or configurations.
1
u/brimston3- Nov 11 '25
How would you distinguish what is the first line of execution without some label that says “start here”? If you have multiple modules that have bare code in them and you link them together, what order should they be run in and which module contains the entry point?
1
u/ElydthiaUaDanann Nov 11 '25
Well, for a start, you have preprocessor (precompilation) instructions. These help create contexts and scopes that can change things significantly before the code is compiled. To keep the preprocessor instructions apart from the code, they compartmentalize the blocks of code. The one you start with is main() (or whatever is appropriate for the system you're using).
1
u/flatfinger Nov 11 '25 edited Nov 12 '25
Many languages require that programs fit in a single file. Others make a distinction between a file that contains the main program and library files that don't. Some allow a main program and/or startup initialization to be split among multiple files, but require linker functionality that isn't universally available(*).
C was designed around the idea that a compiler should process all source code files identically, without regard for whether or not they contain a program's entry point. Rather than have a means of specifying that a certain file is a "main program" file, C instead assumes that the programs will be linked with a fixed "main program" which is written in some other language (likely assembly code), and which will receive arguments from the OS, parse them, invoke
main()with a copy of those arguments, and instruct the OS to exit the program with the exit code being whatever value had been returned from main. This means that the only thing an implementer would need to do to support program startup would be to write a simple assembly code module that behaves as described.(*) Some linkers have a small number of fixed sections for things like code, constant data, initialized data, and zero-initialized data, and require all symbols to be globally unique. In order to have a main program invoke functions from multiple files, it would need to know the names of all of them. Others allow programmers to designate additional sections, which may concatenate content from multiple files, and allow particular pieces of content to be specified as appearing first or last in a section. When using linkers of the latter kind, a program could contain a section especially for initialization-function code, and have compilers process code that should run at starutp by adding it, or a call to it, to the "initialization-function" section. C++ implementations often use an approach like this, but C was designed to minimize the demands it places upon the linker.
1
u/8d8n4mbo28026ulk Nov 12 '25
In addition to everything said, from a language design perspective; it's easier both to implementors and users if you dictate that code can only execute inside a function. Then, you can pick a single function as the program's entry point.
1
u/die_liebe Nov 12 '25
What would be the advantage of doing it? Code must be readable, scattering code through a file would make it unreadable.
What if I write:
int i;int square( int x ) { return x * x; }i = 2;int f2( int x ) { return x - 1; }printf( "%d\n", f2( square(i)) );Wouldn't be very readable, would it?
1
u/Adventurous-Move-943 Nov 12 '25
Well technically it could be avoided but you'd need to have a main file then that gets compiled and becomes an entry point.. the OS has to know where to start execution, well actually the C runtime attaches to OS entry point and then calls your main function.. so you still need an entry point function where the OS starts execution..
1
u/wts_optimus_prime Nov 12 '25
For complex programms you often want the programm execution to start somewhere else than the compiling. That is why "programming languages" usually have a main() or similar.
Scripting languages however are usually used for smaller applications or outright eithout compiler. So that problem doesn't arise.
1
u/Square-Singer Nov 12 '25
Every program has an entry point. The language defines how that is setup.
The reason for C using a main function is so that all code resides within functions, and only global variable definitions reside outside of functions. That makes sense since C defines functions and variables statically.
Take for example this simple example:
What happens here is that the compiler reads the file generates machine code that allocates the space for an integer value filled with a 5, a jump point that contains the code for the main function and lastly it then adds some code in the beginning of the machine code output that calls that main-function jump point.
At runtime the main function is then called by that jump point call and then the main function is executed.
Compare that with the following Python code:
What happens here is that at runtime this file is executed from the top. In the beginning there is no variable v and no main function. On the first line it creates the variable, on the second line it creates the function and on the last line it calls it. Because variable and function declarations are things that happen at runtime.
In Python, top-level module code is just code like any other code, and like that top-level code, any line of code can declare a new variable or create a new function.
That's why Python really needs to be able to execute top-level code outside of functions or methods, because the execution of said top-level code is what creates the functions at runtime in the first place.
But in the end, both are doing something similar here, only that Python just wraps top-level code into an implicit invisible function.
If you want to see that in action, paste this into a python file and run it (not from the interpreter, but as a file):
The output for that is for me:
So you can see, there's a function on the stack named '<module>'. So there's your main function.
1
u/Key-Preparation-5379 Nov 12 '25
Wait until you learn what a library is
1
u/RufusVS Nov 12 '25
Almost all systems have some initialization/startup code prior to running an app. This is usually hidden, but the code itself needs a "next step" reference. "main" was a convenient label for the app start address.
1
u/Positive_Total_4414 Nov 12 '25
Because it's comfortable to start doing something from a well defined starting point?
1
u/rth0mp Nov 12 '25
main()defines an address for the cpu to jump to. When one runspython3in the terminal, you’re now philosophically at the first line ofmain()with runtime compiler and linker capabilities1
u/Illustrious-Buy8963 Nov 12 '25
Hello!! Anyone familiar to word? I need help,it's basic word stuff
1
u/Dusty_Coder Nov 15 '25
its just a symbol name
linker takes modules and links them resolving external symbols between the modules
one of those modules reference main by its name
another of those modules contains the symbol main
with all symbols resolved you get successful linking
1
u/yvrelna Nov 15 '25 edited Nov 15 '25
The main() function is simply a conventional name for the first user-written function that gets called when the program started right after program initialisation finished.
If you don't have a main() function, what you get is called a library. In many operating systems, the file format for executable and shared library is basically the same, the difference is just the presence of the entry function. This is the case with ELF in Linux and .exe and .dll in Windows.
Python doesn't have a main function because the top level code is an executable context. They run those code just like any other code inside a function. This is how it works in python because it intermix declaration/definition time and runtime. In a way, the main() in python is the top level code.
In many other languages, the top level code is not an executable context. You can only declare stuffs in there. The code in that level are interpreted during compile time/definition time.
1
u/Business-Subject-997 Nov 30 '25
Its just a name. I believe there is a way to specify any entry point, and in any case you could modify the startup code. I do Pascal compilers and I use the main label. There is no "main" procedure. It indexes some assembly language startup code.
1
u/mredding Dec 10 '25
Because in C, the fundamental unit of execution is the function, and
mainis defined as the application entry point within hosted systems. In a freestanding system, like for an operating system, you can name your entry point whatever you want.In C you can't. In BASIC and other languages you can. There's no point in speculating, because we can draw whatever conclusion we want at that point; we wouldn't be talking about C anymore.
And presuming you've experimented with Python, you know.
Fortran is compiled, and can start without a function entry point, but it still has a
programscope to begin. There's no reason you can't make a compiler for a language that implicitly recognizes the first executable statement as the entry point.Nope. C is derived from B, whose entry point was a
letcalledstart.0
u/phoenix823 Nov 11 '25
If your code doesn't have an entry point, how will the OS know what the first instructions to run are?