1

Let's say I have the following C code:

int return_one()
{
    return 1;
}

int main(void)
{
    return_one();
}

Within the main function, I call function return_one() and ignore the return value. The compiler has no issue with me ignoring this value.

What is the logic as to why this okay? Was it an arbitrary design choice from the C creators? Or is there a practical reason for not requiring the calling function to use the return value?

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
Izzo
  • 4,461
  • 13
  • 45
  • 82
  • Related: [Ignoring return values in C](https://stackoverflow.com/questions/11888594/ignoring-return-values-in-c) – sleske Apr 16 '22 at 01:33
  • Stack memory allocation is a fundamental concept in C. – Izzo Apr 16 '22 at 01:34
  • 5
    @Izzo. It is not. C does not require not mandate the use of a stack, and there are compiler-architecture combos that do not use one. – ikegami Apr 16 '22 at 01:34
  • 2
    In point of fact, on most modern architectures, the return value comes back in a register, and is often never stored to the stack, even if you save it to a variable (x86-64 ends up storing to the stack more often, because it's relatively register starved, but if the value is used and discarded in short order, it rarely makes it to the stack). – ShadowRanger Apr 16 '22 at 01:37
  • Code could call `frexp` and only want the exponent part that is returned via a pointer and not the fraction that is returned as the return value. When calling `fclose` for a temporary file, a program does not care if the return value indicates it failed to write unbuffered data to disk. After `memcpy`, I already know the return value. – Eric Postpischil Apr 16 '22 at 02:04
  • Why is this tagged with c99, c11, and c89? Those are supposed to be for questions that are specific to their particular version of the language. At most c89 is relevant, since it would have established the matter in the standard, and it did not change in c99 or c11. – Eric Postpischil Apr 16 '22 at 02:09
  • @EricPostpischil OP seems to believe that the C language being okay to ignore return values seems to be a construct of the C language. Thus, design decisions are probably related to language standards (C89, C99, C11). For new Stackoverflow users, tags often bring attention to specialists who specifically subscribe to certain tags (which probably includes yourself) DSP expert from Apple. – Izzo Apr 16 '22 at 02:15
  • 2
    @Izzo: if a question includes the [tag:c89] tag but not the [tag:c] tag, it will probably not be seen by many people — I would only see it by accident. I do not subscribe to any of the C version tags. I suspect I'm in the majority here. (After a quick check on the tags page, [tag:c89] has 109 watchers; [tag:c99] has 413; [tag:c11] has 209; [tag:c17] has 41 ([tag:c18] is for a specific compiler); [tag:c2x] has 5. By contrast, the plain [tag:c] tag has 611.7 thousand watchers — more than a thousand times as many as any of the version-specific tags!) – Jonathan Leffler Apr 16 '22 at 02:22
  • 1
    Select embedded C compilers, common in the 202x have no data stack, just a return address one. Stack memory allocation is not a fundamental concept in C. C is very broad minded in the planforms in which it can be hosted. – chux - Reinstate Monica Apr 16 '22 at 02:37
  • [C2x](https://en.wikipedia.org/wiki/C2x#Features) may have `nodiscard, maybe_unused` to address some of OP's concerns. – chux - Reinstate Monica Apr 16 '22 at 02:41
  • @JonathanLeffler The first tag on this question is the vanilla C tag. – Izzo Apr 16 '22 at 03:03
  • 1
    @Izzo — Yes: that's good and how I spotted the question. The version-specific tags are largely irrelevant because very few people will use them to search for this question. – Jonathan Leffler Apr 16 '22 at 03:04

3 Answers3

3

Because people don't care about a lot of return values, so why force them to use them?

A ton of standard C functions return values that are essentially never looked at. Think about all the C code you've ever looked at. Have you ever seen someone do anything with the return value from the printf family of functions? Because they all have one, but you'd never know it to look at real world code. Would it be improved if every single call to printf had to prefix it with an explicit "I don't care about the return value" bit of syntax (e.g. (void)), because 99.99% of the time, you don't actually care how many bytes you printed, but printf computes and returns it anyway? Basically, you're allowed to not use the return value because there's was no need to force you to do so, and it's often not needed.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
3

I think the main reason is the usual one — history.

Before the C standard, there was no option to use void to indicate 'no return value'. Functions returned an int unless you specified that they returned some other type, but that other type couldn't be void (it didn't exist). So functions for which the return value was immaterial didn't return a value — even though the function was implicitly returning type int. (Usually, the return type was omitted — the function was implicitly returning an int.) You got UB if the calling code tried to use a value but the called function didn't return a value.

All this meant that it was commonplace to ignore the return value of functions — especially functions that nominally returned an int but actually didn't return any value. There wasn't a better way of dealing with it. Nowadays, with void return types, there are better ways to deal with it. Nevertheless, it remains true that the return value is often of limited interest. How often do you check the return value of printf() or one of its friends? How often do you use the return value of strcpy() et al?

C90 had to allow old code to run still, so it allowed the old, pre-standard behaviour. C99 tightened the rules — functions were no longer implicitly of type int and had to be declared (with an explicit return type, possibly void) before they could be used.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Incidentally, with GCC you can specify [`__attribute__((warn_unused_result))`](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes) on a function declaration and then code calling the function but not using the result will generate a warning (an error if you compile with `-Werror`, as you should). Clang is similar. – Jonathan Leffler Apr 16 '22 at 03:17
0

tl;dr: You can write code such that the return values are always relevant - in that case ignoring them would be a bug. However, some (particularly older) code does not work that way, there ignoring return values may be reasonable.

What is the logic as to why this okay? Was it an arbitrary design choice from the C creators?

It is not just a choice by the C creators, many other languages also allow this - as a matter of fact, I cannot think of a language where ignoring the return value is considered an error.

The practical motivation for this is mainly that the return value of a function is often used for reporting errors, or reporting details of what the function did. Sometimes, you are not interested in these details, so you ignore them. A common example of this is the C function printf, which returns the number of characters printed. While this may sometimes be useful, it is usually not, so the return value of printf is usually ignored.

This is arguably a bad design (either in your code, or in the function that returns stuff noone wants), but it is established practice, so C (like other languages) supports this.

Or is there a practical reason for not requiring the calling function to use the return value?

No, there is no practical reason for ignoring return values - unless you do not want them.


While the above is the historical practice, many people now consider ignoring return values a problem (or a symptom of a deeper problem):

  • If the return value is for error reporting, ignoring it will work usually, but cause problems if there really is an error. This is now usually considered a bad idea.
  • Generally, if you can ignore the return value, that means the function is causing side-effects (otherwise calling it would be pointless). Many people think that it is better to have functions only do one thing - either cause a side effect (and return nothing), or return a value (and have no side effects). The latter is often called a pure function (with the additional condition of the output only depending on the input). This separation makes it easier to understand software - and if you use it, ignoring a return value is necessarily a mistake, because functions returning a result do nothing else, so if you ignore the result, calling it is pointless.

So in other words: If you follow certain conventions, there should be no situation where you want to ignore return values, in that case ignoring them is usually a mistake. Without these conventions, there may be good reasons for ignoring them, so there's no general rule.

user3386109
  • 34,287
  • 7
  • 49
  • 68
sleske
  • 81,358
  • 34
  • 189
  • 227