6

From cppref:

std::time_t time(std::time_t* arg);

Returns the current calendar time encoded as a std::time_t object, and also stores it in the object pointed to by arg, unless arg is a null pointer.

I never see anyone call std::time with a non-null pointer argument. I just wonder:

1. Why does std::time have an unnecessary parameter?

2. Is there any motivation/rationale behind the design?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • 2
    It's possible the actual motivation is lost to.............. history. – JohnFilleau Apr 25 '20 at 20:24
  • 3
    My guess for path that lead to this: There may have once upon a time been the function `void time(time_t*)`. Then somebody though that returning the value would be more convenient, and since changing void return value to non-void does not break ABI but removing argument does, we ended up with `time_t time(time_t*)`. I don't know if this is the case, nor why the function would originally have used only the pointer for output. – eerorika Apr 25 '20 at 20:33
  • 3
    See [this](https://stackoverflow.com/a/46025899/2079303) answer of the duplicate in particular. – eerorika Apr 25 '20 at 20:39
  • @eerorika I'm not convinced that that's a good duplicate. The question itself is basically unrelated, and one of the answers just happens to go on a tangent that covers this question. – Joseph Sible-Reinstate Monica Apr 25 '20 at 20:40
  • eerorika's guess is approximately correct, although the historical relic was *not* `void time(time_t*)`, because back when the function was first devised, we didn't have `time_t`, `long`, *or* `void` to play with. See [my answer](https://stackoverflow.com/questions/61432103/why-does-stdtime-have-an-unnecessary-parameter/67836295#67836295) below, copied from that other question to address Joseph Sible's objection. – Steve Summit Jun 04 '21 at 11:27

2 Answers2

4

Historically time_t was an abstract type and there was probably an expectation that it might need to be a structure or extension type that might not be able to be returned reliably, or where compilers might disagree in ABI for returning it, such that returning it by storing it to a caller-provided address "made sense". Note the existence of the difftime interface and C's vagueness about how time_t values are to be interpreted. Only POSIX (much later) required the unit to be seconds (since the epoch, and defined the epoch). I'm not sure if there's any concrete evidence for this as the motivation (maybe in the C89 Rationale document?) but this is the area I'd look in.

For C++, it's simply that the std::time interface is the C time function, wrapped in std::.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • I wouldn't say that "Only POSIX (much later) required the unit to be seconds... and defined the epoch". Unix has been using seconds-since-1970 ever since, well, about 1970. X3J11 introduced the allegedly-abstract type `time_t`, which could theoretically be defined in some other way. So then Posix turned around and said that its `time_t` was seconds-since-1970, just as it has always been. Yes, `difftime` was part of the same attempt at abstraction, but in practice, implementation choices other than Posix's have been vanishingly rare. – Steve Summit Jun 04 '21 at 11:24
1

[This answer is adapted from a very similar answer to a slightly different question.]

std::time() has an "extra argument" because it's the same as C's time() function, which is very, very old. It goes back to the dawn of C, when the language didn't even have type long. Once upon a time, the only way to get something like a 32-bit type was to use an array of two ints — and that was when ints were 16 bits.

So you called

int now[2];
time(now);

and time filled the 32-bit time into now[0] and now[1], 16 bits at a time. If you wanted to print the time in human-readable format, you called ctime(int *), which also accepted the time as a pointer, for basically the same reason.

Later on, dmr finished adding long to the compiler, so you could start saying

long now;
time(&now);

At about the same time, someone realized it'd be useful if time() went ahead and returned the value, now that it could, rather than just filling it in via a pointer. But — backwards compatibility is a wonderful thing — for the benefit of all the code that was still doing time(&now), the time() function had to keep supporting the pointer argument. Which is why — and this is why backwards compatibility is not always such a wonderful thing, after all — if you were using the return value, you still had to pass NULL as a pointer:

long now = time(NULL);

Later still, we started using time_t instead of plain long for times, so that, for example, it can be changed to a 64-bit type, dodging the y2.038k problem.

So, in summary, the "extra argument" is a historical relic, left over from a time when it was impossible for time() to simply return the time, because there was no suitable return type. Moreover, the extra argument had to be a pointer, to a data structure to be filled in, because that data structure — an array — couldn't be simply returned by a function, either.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103