This question already has answers here:
What is a good general approach for deciding return values in C?
(8 answers)
Closed 8 years ago.
I was wondering whether there are any pre-agreed values, coming from the old days of C language, that reflect tha function execution threw exception/terminated abruptly/failed for any reason? Is this value 0, or -1 or is it completely up to you and no standards exist?
Functions that return pointers usually return NULL to indicate failure (e.g. malloc).
Most POSIX functions return 0 on success, and non-zero on failure. If they need to return a non-zero value as part of normal operation, they often return a negative value on failure.
But this is all just convention.
One common convention is to return an invalid value, whatever it is. For instance, functions returning lengths may return -1 on failure.
General purpose error codes tend to be 0 or NULL to mimick malloc's behavior. POSIX, on the other hand, uses the inverse convention.
Be sure to get accustomed to errno for more "advanced" error checking. Many standard library routines put an error code there to be checked on failure.
Related
I previously read that 0 in C-Language refers to false while 1 is true.
And have noticed that the main function returns 0 but why is that? in case all of my code ran successfully it should return true (1).
Another related question, I still can't understand who can use the returnable value? since no other function called the main function inside my program so nothing can know if my program ran well or not.
I am a little bit confused.
Your logic would make sense if the return value of main were interpreted as a Boolean value, but it isn't. Returning from the initial call to main is like calling the exit function: It reports a termination status to the system you're running on.
Standard C specifies 3 portable exit statuses:
0, indicating success
EXIT_SUCCESS, also indicating success
EXIT_FAILURE, indicating failure
(The last two are macros defined in <stdlib.h>.)
On Unix, any 8-bit value (0 .. 255) is allowed. All non-zero values are interpreted as error codes. There is no universal convention for what any given number means, just that 0 represents success and anything else some kind of failure.
As for who can use the return value: On Unix, a parent process can use wait or waitpid to get the exit status of a terminated child.
In the C standard library, functions that perform an action generally don't return a true/false status. (Tests such as islower or isdigit do, but they don't have any other effects.) For example, remove (which deletes a file) returns 0 on success and -1 on error. This is also a common pattern with Unix system calls. For exmple, open returns a file descriptor (a non-negative integer) on success and -1 on error.
It's essentially what #Brandon already said in the comments.
main is supposed to return the exit/error code of the program. In the Unix convention, 0 is used to indicate no error (the error value is "false"). And then positive values are used for indicating that there is an error and what error it was.
It's really just about the kind of question you ask a program when it finish.
Case 1:
Did you fail?
Case 2:
Did you pass?
In the first case a "good program" will return false (aka zero)
In the second case a "good program" will return true (aka non-zero).
Consensus is to use Case 1, i.e. "Did you fail?". Therefore a non-failing program returns zero to say "I did not fail".
The benefit of this approach is that non-zero values can be used to expressed different kind of failures while zero is alway "no failure"
There's a difference between what the C language considers true (non-zero) or false (zero) and what value(s) the operating system uses to indicate a normal program termination.
To be strictly correct, C programs should exit with a code of either EXIT_SUCCESS for normal program termination or EXIT_FAILURE for abnormal termination. EXIT_SUCCESS will map to whatever code the underlying platform uses to indicate success, which may or may not be 0.
This question already has answers here:
Return Code on failure. Positive or negative?
(6 answers)
Closed 4 years ago.
Either I didn't searched well or this question is obvious.
In c, the main function returns what You want. But since Posix gives the example, 0 is for success and other values are for fail (mostly positive values in Linux).
Based on this assumption, I have seen a practive where all other functions in the code have the same behaviour.
Pros:
practical because you can return the result of your call directly as the result of your main
Cons:
0 becomes OK, 1 becomes KO.
I am sure it is not good, but I have here 2 million lines based on that.
Is that common ? Does it have a name ?
Returning 0 for success is common. There is no specific name for such behavior.
This is what the C standard says:
7.22.4.4 The exit function
...
2. The exit function causes normal program termination to occur.
...
5. Finally, control is returned to the host environment. If the value of status is zero or EXIT_SUCCESS, an implementation-defined form of the status successful termination is returned. If the value of status is EXIT_FAILURE, an implementation-defined form of the status unsuccessful termination is returned. Otherwise the status returned is implementation-defined.
Most functions that returns a handle, such as OpenProcess, OpenFile, OpenThread, FindWindow, etc, return 0 upon failure. I understand that return an invalid result to indicate failure is a good practice. However, if windows choose -1 to be the INVALID_HANDLE_VALUE, why don't these functions return -1 upon failure?
There are many conjectures you can make, but yes the reasons are historical and due to compatibility in the process of porting old 16bits code to newer one.
Some functions originally returned -1 when failing, in the respect of C habit to return negative values on failure.
Moving to new 32bits versions, for the reason of compatibility mentioned above, lead to the creation of INVALID_HANDLE_VALUE equated to -1.
But because the handles sometimes were real pointers, and for the simplicity of comparison for NULL value many new functions were designed to return NULL on failure.
One interesting point is that INVALID_HANDLE_VALUE happens to be numerically equal to the pseudohandle returned by GetCurrentProcess(). So using an invalid handle in some functions could lead to valid results or terrible deadlocks as in the case of INVALID_HANDLE_VALUE used in a call to WaitForSingleObject. This will lead to an endless wait for the current process.
You can find the whole story, told from the authors, here https://blogs.msdn.microsoft.com/oldnewthing/20040302-00/?p=40443
Currently I'm returning -1 in my custom functions in C if something wrong happens and 0 for success. For instance, working with a linked list and some function needs a non-empty list to work properly. If the list passed as argument is empty, I return -1 (error) and 0 if it's not empty and the function worked without a problem.
Should I, maybe, return 1 instead of -1?
Is this the standard way of doing things in C or do you recommend a different approach?
Return a non-zero value to indicate failure. This way you can write you functions calls as so:
if(func_call())
{
doErrorHandling();
}
This convention will allow you to use any !0 value to indicate a specific error, and this will allow you to use one variable in a uniform fashion. So the body of the if shown in the example above can then have a switch statement to process the specific errors.
You can do it differently -- but if you choose to do so stick to a convention -- the win32 API (and other API's I have used) mix and match conventions unfortunately.
That sounds fine. -1 is used in I/O function because a positive return value usually means success and is the number of bytes that were processed. If you have multiple ways a function can go wrong, then you can either return different integers or set a global error variable (errno is used by the standard library) to contain the error code.
In terms of style, I prefer not to return status codes as it means my functions can't (cleanly) return anything else. Instead I would check the input before calling the function. But this is subjective and depends on the context.
I suggest that you find a way to format a fully-informative human-readable string at the point of the error, where all information is still available, and design a way to get it down thru the rest of the program, thru the user, his mobile phone, to your development team for the analysis.
This seems to me like an important feature of any design, if you want to produce better software faster. Killing error information on the way is a major crime, and C language is no excuse.
There are many schemes - but whatever you do, do it consistently!
If you don't have many failing conditions, just use 0 for error. That's because error tests are written in a simple way:
if (!list_insert(...)) { handle_error; }
Otherwise below-zero answers are good to use along with normal answers >= 0. You can use this for functions like list length, which in normal conditions will not be negative. Or if you want many error codes (-1 - nonexistant, -2 - not found, -3 ..., ...)
Another simple example:
if (wpa_s->mlme.ssid_len == 0)
return -EINVAL;
Why the unary minus? Is this (usually) done for functions that return >0 on success and <(=)0 on failure, or is there some other reason?
First, this isn't really a C thing. You're looking at a function that is written in C for some purpose. The same conventions could be used in any language.
Back in my old Unix days, there was something of a convention that 0 meant success, a positive number meant minor problems, and a negative number meant some sort of failure. Therefore, there was also a sort of convention of if (foo() >= 0) { /* success of a sort */ }.
This was doubtless related to Unix process return codes, where 0 was success.
That's basically the reasons. Lots of functions have lots of "good" positive results, so that leaves the negative values for error codes.
C / POSIX error codes are a bit "historically grown," so there's not much sense in trying to attribute too much rhyme or reason to them.
Many more modern languages throw exceptions for errors so that they don't have to hijack part of their possible response range for error codes. Of course there are trade-offs either way.
Your understanding is broadly correct. The obvious interpretation is the right one.
The standard convention is slightly different than your formula, however.
In Unix, a program that exits with 0 status tests as true or success to CLI-level utilities like the shell. In the library, -1 is usually an error return.
This leads to a general paradigm where >= 0 means good and < 0 means error. None of this is set in stone.
BTW, this might be classified as the sentinel pattern and you could call it a sentinel return. It's actually a combination of a sentinel "value" and an error code, and it's easier to type and easier to make thread-safe than returning an error code in one place and a sentinel value for error in another.
Wikipedia reports that a sentinel value is used to terminate a loop, but I would think that a function return would be a far more common instance. No one is precisely in charge of these definitions.
From an optimization perspective, using negative numbers allows Unix-based kernels to check for an error code using only one comparison instead of two.
Functions in the kernel frequently return error codes in place of pointers. This means that the error codes can't overlap with valid pointer addresses, so they'd basically have to be either the lowest unsigned values (>= 0) or the highest ones (<= unsigned max).
Checking pointer values for NULL and for error codes are extremely common operations, so it makes sense to optimize them.
Typically the bottom values < 0x8000 are NULL and the top values are error codes (remember that -1 is stored as 0xff...ff, the maximum possible unsigned value).
This means that you can use one comparison to check for each:
NULL if x <= 0x8000 (true for 0 to 0x8000)
ERRNO if x >= (unsigned long)(-MAX_ERRNO) (true for -1 to -MAX_ERRNO)
You can see this happening in Linux's err.h file.