The main return value is passed to the exit function.
The exit function's argument is declared as an int, and you can legally pass any int value to it. On UNIX-like systems, all but the low-order 8 bits of the argument are quietly ignore. For example, exit(INT_MAX); is perfectly legal, but it's equivalent to exit(255); (or exit(-1); for that matter).
In Windows you have 32 bits, but one particular value (STILL_ACTIVE = 259 which means process still running) that you must avoid just above the byte value range.
The C++ standard defines just three possible values: 0 (which means success), EXIT_SUCCESS and EXIT_FAILURE, the latter two macro symbols from <stdlib.h> (where also the exit function is declared).
In Unix-land and Windows EXIT_SUCCESS is defined as 0, which is allowed by the standard.
Unfortunately, in Windows, where it's common to use the process exit code to communicate a low level error code, EXIT_FAILURE is typically/always defined as 1 instead of as E_FAIL. Which means that even for a program documented as returning an error code or HRESULT as exit code, you have to beware of the value 1. It's possibly just EXIT_FAILURE.