35

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?

exscape
  • 2,185
  • 4
  • 21
  • 25
  • 43
    Because we don't like anything less than SUCCESS! – Doug T. Dec 04 '09 at 18:18
  • 2
    I don't get why people put a tag "[C]" in the title of a question. Each question always links what its tags are (e.g. the question is currently tagged [c], [errno], [return-value]. Why didn't you title the question "[C] [errno] [return-value] Why return a negative errno? (e.g. return -EIO)"??? – Pete Dec 04 '09 at 18:24
  • 1
    I looked at the question's title and immediately had a seizure, followed by deep coma. If I didn't have a rapid response team of world-class brain surgeons on my premises at all times, who knows if I'd recovered in time to answer the question? – Carl Smotricz Dec 04 '09 at 18:27
  • I put the language in the title because it's easier for people, at least for me, to spot it when looking through the list of questions, despite it being in the list of tags as well. – exscape Dec 04 '09 at 18:31
  • I say here putting the language in the title was not necessary. When you talking about something like "My accordion doesn't work" This could be done as "My accordion doesn't work [ASP.Net]" because it is a very ambiguous title because it could refer to a javascript made control or jquery or whatever else there is out there.. but enough meta talk lol – Earlz Dec 04 '09 at 18:57
  • 1
    Tags are enough for me, SO takes care of highlighting the messages with tags I'm interested in. "[C]" is just noisy for me (but I respect your tastes and won't edit the title :) ) – Remo.D Dec 04 '09 at 21:07
  • Returning `-Exxx` is a convention originating on the Linux Kernel (AFAIK). The typical Unix convention for userspace would be to set `errno` to `Exxx` and return `-1`. – ninjalj Apr 28 '15 at 19:36

4 Answers4

23

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.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
  • Cited you here on similar question [Unix&Linux:"What does exit 99 means?"](http://unix.stackexchange.com/a/125333/11836) – smci Apr 18 '14 at 06:49
18

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.

Carl Smotricz
  • 66,391
  • 18
  • 125
  • 167
  • 11
    There at least used to be a tendency to define 0 as success, positive as successful with problems, and negative as unsuccessful - at least in my old Unix days. – David Thornley Dec 04 '09 at 18:39
  • This doesn't explain the next logical question: why isn't EIO negative? – Carl Mastrangelo Mar 22 '22 at 00:04
  • Disclaimer: I haven't bothered to research this. My guess: EIO is shared with other functions, some of which return the value without negating it. Functions without positive success results, most likely. – Carl Smotricz Mar 27 '22 at 11:42
8

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.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
7

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.

vestlen
  • 1,103
  • 11
  • 17