Files
2025-10-25 03:02:53 +03:00

516 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[basic.start]
# 6 Basics [[basic]](./#basic)
## 6.10 Program execution [[basic.exec]](basic.exec#basic.start)
### 6.10.3 Start and termination [basic.start]
#### [6.10.3.1](#main) main function [[basic.start.main]](basic.start.main)
[1](#main-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7129)
A program shall contain exactly one function called main that belongs to the global scope[.](#main-1.sentence-1)
Executing a program starts a main thread of execution ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"), [[thread.threads]](thread.threads "32.4Threads"))
in which the main function is invoked[.](#main-1.sentence-2)
It is implementation-defined
whether a program in a freestanding environment is required to define a main function[.](#main-1.sentence-3)
[*Note [1](#main-note-1)*:
In a freestanding environment, startup and termination isimplementation-defined; startup contains the
execution of constructors for non-local objects with static storage duration;
termination contains the execution of destructors for objects with static storage
duration[.](#main-1.sentence-4)
— *end note*]
[2](#main-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7147)
An implementation shall not predefine the main function[.](#main-2.sentence-1)
Its type shall have C++ language linkage
and it shall have a declared return type of typeint, but otherwise its type is implementation-defined[.](#main-2.sentence-2)
An implementation shall allow both
- [(2.1)](#main-2.1)
a function of () returning int and
- [(2.2)](#main-2.2)
a function of (int, pointer to pointer to char) returning int
as the type of main ([[dcl.fct]](dcl.fct "9.3.4.6Functions"))[.](#main-2.sentence-3)
In the latter form, for purposes of exposition, the first function
parameter is called argc and the second function parameter is
called argv, where argc shall be the number of
arguments passed to the program from the environment in which the
program is run[.](#main-2.sentence-4)
Ifargc is nonzero these arguments shall be supplied inargv[0] through argv[argc - 1] as pointers to the initial
characters of null-terminated multibyte strings (ntmbss) ([[multibyte.strings]](multibyte.strings "16.3.3.3.4.3Multibyte strings"))
and argv[0] shall be the pointer to
the initial character of an ntmbs that represents the name used to
invoke the program or ""[.](#main-2.sentence-5)
The value of argc shall be
non-negative[.](#main-2.sentence-6)
The value of argv[argc] shall be 0[.](#main-2.sentence-7)
*Recommended practice*: Any further (optional) parameters should be added after argv[.](#main-2.sentence-8)
[3](#main-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7179)
The function main shall not be named by an expression[.](#main-3.sentence-1)
The linkage ([[basic.link]](basic.link "6.7Program and linkage")) of main isimplementation-defined[.](#main-3.sentence-2)
A program that defines main as
deleted or that declares main to beinline, static, constexpr, or consteval is ill-formed[.](#main-3.sentence-3)
The function main shall not be a coroutine ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4Coroutine definitions"))[.](#main-3.sentence-4)
The main function shall not be declared with a[*linkage-specification*](dcl.link#nt:linkage-specification "9.12Linkage specifications[dcl.link]") ([[dcl.link]](dcl.link "9.12Linkage specifications")) other than "C++"[.](#main-3.sentence-5)
A program that declares
- [(3.1)](#main-3.1)
a variable main that belongs to the global scope, or
- [(3.2)](#main-3.2)
a function main that belongs to the global scope and
is attached to a named module, or
- [(3.3)](#main-3.3)
a function template main that belongs to the global scope, or
- [(3.4)](#main-3.4)
an entity named main with C language linkage (in any namespace)
is ill-formed[.](#main-3.sentence-6)
The name main is
not otherwise reserved[.](#main-3.sentence-7)
[*Example [1](#main-example-1)*:
Member functions, classes, and
enumerations can be called main, as can entities in other
namespaces[.](#main-3.sentence-8)
— *end example*]
[4](#main-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7211)
Terminating the program
without leaving the current block (e.g., by calling the functionstd::exit(int) ([[support.start.term]](support.start.term "17.5Startup and termination"))) does not destroy any
objects with automatic storage duration ([[class.dtor]](class.dtor "11.4.7Destructors"))[.](#main-4.sentence-1)
Ifstd::exit is invoked during the destruction of
an object with static or thread storage duration, the program has undefined
behavior[.](#main-4.sentence-2)
[5](#main-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7223)
A return statement ([[stmt.return]](stmt.return "8.8.4The return statement")) in main has the effect of leaving the main function (destroying any objects with automatic storage duration
and evaluating any postcondition assertions of main)
and calling std::exit with the return value as the argument[.](#main-5.sentence-1)
If control flows off the end of
the [*compound-statement*](stmt.block#nt:compound-statement "8.4Compound statement or block[stmt.block]") of main,
the effect is equivalent to a return with operand 0 (see also [[except.handle]](except.handle "14.4Handling an exception"))[.](#main-5.sentence-2)
#### [6.10.3.2](#static) Static initialization [[basic.start.static]](basic.start.static)
[1](#static-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7238)
Variables with static storage duration
are initialized as a consequence of program initiation[.](#static-1.sentence-1)
Variables with
thread storage duration are initialized as a consequence of thread execution[.](#static-1.sentence-2)
Within each of these phases of initiation, initialization occurs as follows[.](#static-1.sentence-3)
[2](#static-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7246)
[*Constant initialization*](#def:constant_initialization "6.10.3.2Static initialization[basic.start.static]") is performed
if a variable with static or thread storage duration
is constant-initialized ([[expr.const]](expr.const "7.7Constant expressions"))[.](#static-2.sentence-1)
If constant initialization is not performed, a variable with static
storage duration ([[basic.stc.static]](basic.stc.static "6.8.6.2Static storage duration")) or thread storage
duration ([[basic.stc.thread]](basic.stc.thread "6.8.6.3Thread storage duration")) is zero-initialized ([[dcl.init]](dcl.init "9.5Initializers"))[.](#static-2.sentence-2)
Together, zero-initialization and constant initialization are called[*static initialization*](#def:initialization,static "6.10.3.2Static initialization[basic.start.static]");
all other initialization is [*dynamic initialization*](#def:initialization,dynamic "6.10.3.2Static initialization[basic.start.static]")[.](#static-2.sentence-3)
All static initialization strongly happens before ([[intro.races]](intro.races "6.10.2.2Data races"))
any dynamic initialization[.](#static-2.sentence-4)
[*Note [1](#static-note-1)*:
The dynamic initialization of non-block variables is described
in [[basic.start.dynamic]](#dynamic "6.10.3.3Dynamic initialization of non-block variables"); that of static block variables is described
in [[stmt.dcl]](stmt.dcl "8.10Declaration statement")[.](#static-2.sentence-5)
— *end note*]
[3](#static-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7266)
An implementation is permitted to perform the initialization of a
variable with static or thread storage duration as a static
initialization even if such initialization is not required to be done
statically, provided that
- [(3.1)](#static-3.1)
the dynamic version of the initialization does not change the
value of any other object of static or thread storage duration
prior to its initialization, and
- [(3.2)](#static-3.2)
the static version of the initialization produces the same value
in the initialized variable as would be produced by the dynamic
initialization if all variables not required to be initialized statically
were initialized dynamically[.](#static-3.sentence-1)
[*Note [2](#static-note-2)*:
As a consequence, if the initialization of an object obj1 refers to an
object obj2 potentially requiring dynamic initialization and defined
later in the same translation unit, it is unspecified whether the value of obj2 used
will be the value of the fully initialized obj2 (because obj2 was statically
initialized) or will be the value of obj2 merely zero-initialized[.](#static-3.sentence-2)
For example,inline double fd() { return 1.0; }extern double d1;double d2 = d1; // unspecified:// either statically initialized to 0.0 or// dynamically initialized to 0.0 if d1 is// dynamically initialized, or 1.0 otherwisedouble d1 = fd(); // either initialized statically or dynamically to 1.0
— *end note*]
#### [6.10.3.3](#dynamic) Dynamic initialization of non-block variables [[basic.start.dynamic]](basic.start.dynamic)
[1](#dynamic-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7302)
Dynamic initialization of a non-block variable with static storage duration is
unordered if the variable is an implicitly or explicitly instantiated
specialization, is partially-ordered if the variable
is an inline variable that is not an implicitly or explicitly instantiated
specialization, and otherwise is ordered[.](#dynamic-1.sentence-1)
[*Note [1](#dynamic-note-1)*:
A non-inline explicit specialization of a templated variable
has ordered initialization[.](#dynamic-1.sentence-2)
— *end note*]
[2](#dynamic-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7316)
A declaration D is[*appearance-ordered*](#def:appearance-ordered "6.10.3.3Dynamic initialization of non-block variables[basic.start.dynamic]") before a declaration E if
- [(2.1)](#dynamic-2.1)
D appears in the same translation unit as E, or
- [(2.2)](#dynamic-2.2)
the translation unit containing E has an interface dependency on the translation unit containing D,
in either case prior to E[.](#dynamic-2.sentence-1)
[3](#dynamic-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7326)
Dynamic initialization of non-block variables V and W with static storage duration are ordered as follows:
- [(3.1)](#dynamic-3.1)
If V and W have ordered initialization and
the definition of V is appearance-ordered before the definition of W, or
if V has partially-ordered initialization,W does not have unordered initialization, and
for every definition E of W there exists a definition D of V such that D is appearance-ordered before E, then
* [(3.1.1)](#dynamic-3.1.1)
if the program does not start a thread ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))
other than the main thread ([[basic.start.main]](#main "6.10.3.1main function"))
or V and W have ordered initialization and
they are defined in the same translation unit,
the initialization of V is sequenced before
the initialization of W;
* [(3.1.2)](#dynamic-3.1.2)
otherwise,
the initialization of V strongly happens before
the initialization of W[.](#dynamic-3.1.sentence-1)
- [(3.2)](#dynamic-3.2)
Otherwise, if the program starts a thread
other than the main thread
before either V or W is initialized,
it is unspecified in which threads
the initializations of V and W occur;
the initializations are unsequenced if they occur in the same thread[.](#dynamic-3.2.sentence-1)
- [(3.3)](#dynamic-3.3)
Otherwise, the initializations of V and W are indeterminately sequenced[.](#dynamic-3.3.sentence-1)
[*Note [2](#dynamic-note-2)*:
This definition permits initialization of a sequence of
ordered variables concurrently with another sequence[.](#dynamic-3.sentence-2)
— *end note*]
[4](#dynamic-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7371)
A [*non-initialization odr-use*](#def:odr-use,non-initialization "6.10.3.3Dynamic initialization of non-block variables[basic.start.dynamic]") is an odr-use ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3One-definition rule")) not caused directly or indirectly by
the initialization of a non-block static or thread storage duration variable[.](#dynamic-4.sentence-1)
[5](#dynamic-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7377)
It is implementation-defined
whether the dynamic initialization of a
non-block non-inline variable with static storage duration
is sequenced before the first statement of main or is deferred[.](#dynamic-5.sentence-1)
If it is deferred, it strongly happens before
any non-initialization odr-use
of any non-inline function or non-inline variable
defined in the same translation unit as the variable to be initialized[.](#dynamic-5.sentence-2)[38](#footnote-38 "A non-block variable with static storage duration having initialization with side effects is initialized in this case, even if it is not itself odr-used ([term.odr.use], [basic.stc.static]).")
It is implementation-defined
in which threads and at which points in the program such deferred dynamic initialization occurs[.](#dynamic-5.sentence-3)
*Recommended practice*: An implementation should choose such points in a way
that allows the programmer to avoid deadlocks[.](#dynamic-5.sentence-4)
[*Example [1](#dynamic-example-1)*: // - File 1 -#include "a.h"#include "b.h" B b;
A::A() { b.Use();}// - File 2 -#include "a.h" A a;
// - File 3 -#include "a.h"#include "b.h"extern A a;extern B b;
int main() { a.Use();
b.Use();}
It is implementation-defined
whether either a or b is
initialized before main is entered or whether the
initializations are delayed until a is first odr-used inmain[.](#dynamic-5.sentence-5)
In particular, if a is initialized beforemain is entered, it is not guaranteed that b will be
initialized before it is odr-used by the initialization of a, that
is, before A::A is called[.](#dynamic-5.sentence-6)
If, however, a is initialized
at some point after the first statement of main, b will
be initialized prior to its use in A::A[.](#dynamic-5.sentence-7)
— *end example*]
[6](#dynamic-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7437)
It is implementation-defined
whether the dynamic initialization of a
non-block inline variable with static storage duration
is sequenced before the first statement of main or is deferred[.](#dynamic-6.sentence-1)
If it is deferred, it strongly happens before
any non-initialization odr-use
of that variable[.](#dynamic-6.sentence-2)
It is implementation-defined
in which threads and at which points in the program such deferred dynamic initialization occurs[.](#dynamic-6.sentence-3)
[7](#dynamic-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7448)
It is implementation-defined
whether the dynamic initialization of a
non-block non-inline variable with thread storage duration
is sequenced before the first statement of the initial function of a thread or is deferred[.](#dynamic-7.sentence-1)
If it is deferred,
the initialization associated with the entity for thread *t* is sequenced before the first non-initialization odr-use by *t* of any non-inline variable with thread storage duration
defined in the same translation unit as the variable to be initialized[.](#dynamic-7.sentence-2)
It is implementation-defined
in which threads and at which points in the program such deferred dynamic initialization occurs[.](#dynamic-7.sentence-3)
[8](#dynamic-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7461)
If the initialization of
a non-block variable with static or thread storage duration
exits via an exception,
the function std::terminate is called ([[except.terminate]](except.terminate "14.6.2The std::terminate function"))[.](#dynamic-8.sentence-1)
[38)](#footnote-38)[38)](#footnoteref-38)
A non-block variable with static storage duration
having initialization
with side effects is initialized in this case,
even if it is not itself odr-used ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3One-definition rule"), [[basic.stc.static]](basic.stc.static "6.8.6.2Static storage duration"))[.](#footnote-38.sentence-1)
#### [6.10.3.4](#term) Termination [[basic.start.term]](basic.start.term)
[1](#term-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7470)
Constructed objects ([[dcl.init]](dcl.init "9.5Initializers"))
with static storage duration are destroyed
and functions registered with std::atexit are called as part of a call tostd::exit ([[support.start.term]](support.start.term "17.5Startup and termination"))[.](#term-1.sentence-1)
The call to std::exit is sequenced before
the destructions and the registered functions[.](#term-1.sentence-2)
[*Note [1](#term-note-1)*:
Returning from main invokes std::exit ([[basic.start.main]](#main "6.10.3.1main function"))[.](#term-1.sentence-3)
— *end note*]
[2](#term-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7487)
Constructed objects with thread storage duration within a given thread
are destroyed as a result of returning from the initial function of that thread and as a
result of that thread calling std::exit[.](#term-2.sentence-1)
The destruction of all constructed objects with thread storage
duration within that thread strongly happens before destroying
any object with static storage duration[.](#term-2.sentence-2)
[3](#term-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7495)
If the completion of the constructor or dynamic initialization of an object with static
storage duration strongly happens before that of another, the completion of the destructor
of the second is sequenced before the initiation of the destructor of the first[.](#term-3.sentence-1)
If the completion of the constructor or dynamic initialization of an object with thread
storage duration is sequenced before that of another, the completion of the destructor
of the second is sequenced before the initiation of the destructor of the first[.](#term-3.sentence-2)
If an object is
initialized statically, the object is destroyed in the same order as if
the object was dynamically initialized[.](#term-3.sentence-3)
For an object of array or class
type, all subobjects of that object are destroyed before any block
variable with static storage duration initialized during the construction
of the subobjects is destroyed[.](#term-3.sentence-4)
If the destruction of an object with static or thread storage duration
exits via an exception,
the function std::terminate is called ([[except.terminate]](except.terminate "14.6.2The std::terminate function"))[.](#term-3.sentence-5)
[4](#term-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7512)
If a function contains a block variable of static or thread storage duration that has been
destroyed and the function is called during the destruction of an object with static or
thread storage duration, the program has undefined behavior if the flow of control
passes through the definition of the previously destroyed block variable[.](#term-4.sentence-1)
[*Note [2](#term-note-2)*:
Likewise, the behavior is undefined
if the block variable is used indirectly (e.g., through a pointer)
after its destruction[.](#term-4.sentence-2)
— *end note*]
[5](#term-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7523)
If the completion of the initialization of an object with static storage
duration strongly happens before a call to std::atexit (see[<cstdlib>](cstdlib.syn#header:%3ccstdlib%3e "17.2.2Header <cstdlib> synopsis[cstdlib.syn]"), [[support.start.term]](support.start.term "17.5Startup and termination")), the call to the function passed tostd::atexit is sequenced before the call to the destructor for the object[.](#term-5.sentence-1)
If a
call to std::atexit strongly happens before the completion of the initialization of
an object with static storage duration, the call to the destructor for the
object is sequenced before the call to the function passed to std::atexit[.](#term-5.sentence-2)
If a
call to std::atexit strongly happens before another call to std::atexit, the
call to the function passed to the second std::atexit call is sequenced before
the call to the function passed to the first std::atexit call[.](#term-5.sentence-3)
[6](#term-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7537)
If there is a use of a standard library object or function not permitted within signal
handlers ([[support.runtime]](support.runtime "17.14Other runtime support")) that does not happen before ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))
completion of destruction of objects with static storage duration and execution ofstd::atexit registered functions ([[support.start.term]](support.start.term "17.5Startup and termination")), the program has
undefined behavior[.](#term-6.sentence-1)
[*Note [3](#term-note-3)*:
If there is a use of an object with static storage
duration that does not happen before the object's destruction, the program has undefined
behavior[.](#term-6.sentence-2)
Terminating every thread before a call to std::exit or the exit frommain is sufficient, but not necessary, to satisfy these requirements[.](#term-6.sentence-3)
These
requirements permit thread managers as static-storage-duration objects[.](#term-6.sentence-4)
— *end note*]
[7](#term-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7551)
Calling the function std::abort() declared in[<cstdlib>](cstdlib.syn#header:%3ccstdlib%3e "17.2.2Header <cstdlib> synopsis[cstdlib.syn]") terminates the program without executing any destructors
and without calling
the functions passed to std::atexit() or std::at_quick_exit()[.](#term-7.sentence-1)