The source code written in C++ must be compiled (i.e. translated to the machine code) by one or another compiler such as Embarcadero RAD Studio C++ compilers before in can be runned. In general, there are two types of the resulting machine code: library and main executable (hereinafter simply executable). This post will briefly cover the later of these two.
When an executable produced from a C++ source code starts an operating system calls the global function main()
. There only two possible signatures of the main()
function:
1 2 |
int main(); // (1) int main(int argc, char* argv[]); // (2) |
In case (1)
the main()
function does not accepts any arguments. By defining the main()
function this way, it’s not possible to access the command line arguments which are passed to an executable upon the start. On the contrary, in the case (2)
, the program argument count and the program argument values are available from within the main()
function through the argc
and argv
variables accordingly.
In both cases the value of type int
returned by the main()
function indicates so called exit status. Usually, this value can be obtained by using the command shell facility immediately after the program exit. By convention, the returned value of 0
indicates a successful program completion, while nonzero value indicates a failure. Often the different nonzero values are used to distinguish between the failures. If no value is returned explicitly an operating system will receive zero exit status indicating successful completion implicitly.
Accessing the command line arguments
As mentioned above, it’s possible to access command line arguments passed to an executable upon start if the main()
function defined with two arguments. For example, the C++ program that nicely prints both the path of the executable and the arguments specified upon the start via the command line might looks as follow:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <cassert> #include <iostream> #include <iterator> int main(const int argc, const char* const argv[]) { assert(argc > 0); // `argc` is always positive auto* const executable = argv[0]; // `argv[0]` is always the path // that specified upon the start // of the executable const int rest_argc = argc - 1; // count of rest of argv starting // with index 1 std::cout << "Main executable " << executable << " is started with " << rest_argc << " arguments"; if (rest_argc) { // argv[1], ..., argv[argc - 1] are always // the arguments of the executable std::cout << ":\n"; std::copy(argv + 1, argv + argc, std::ostream_iterator<const char*>{std::cout, "\n"}); } else std::cout << ".\n"; } |
Please note, that the argc
and argv
are declared as constants, which allows to hedge against theirs accidental modification. Also note, that the value of argc
is always positive, because the value of argv[0]
is always denotes the path of the executable specified when it starts. Finally, if there are arguments passed to the executable through the command line, they are always accessible as a sequence in range of [argv + 1, argv + argc)
.