Question

If the user type time_t is defined as __darwin_time_t, which itself is defined as long in MacOS X, why does the following code outputs 8 Time is (null)? Maybe it's something silly, but I can't really understand it.

#include <stdio.h>
#include <time.h>

int main(void)
{
    time_t time = 0x7FFFFFFFFFFFFFFF;

    printf("%lu\n"
           "Time is %s\n", sizeof(time_t), ctime(&time));

    return 0;
}
Was it helpful?

Solution

Time 0x7FFFFFFFFFFFFFFF appears to be around the year 292,471,210,647 AD, which undoubtedly causes ctime to exceed the 26 characters it is guaranteed by C99, so it returns NULL rather than overflowing its buffer. In general, try to avoid any dates that occur after the Morlocks go to war with the Eloi.

OTHER TIPS

While working through the book "Expert C Programming", I ran across the same problem in Lion 10.7.3 -- with t=0xf0c00000000000, ctime(&t) yields Wed Mar 1 21:07:12 214739252 and with t=0xf0d00000000000, ctime(&t) returns the null pointer (0x0). So it doesn't appear to be a wrap around for t, but some test inside ctime(&t) that returns the null pointer if t is too large.

From glibc's implementation we read:

We limit the size of the year which can be printed. Using the %d format specifier used the addition of 1900 would overflow the number and a negative vaue is printed. For some architectures we could in theory use %ld or an evern larger integer format but this would mean the output needs more space. This would not be a problem if the 'asctime_r' interface would be defined sanely and a buffer size would be passed.

Run the program below to find the exact limit on your machine.

#include <limits.h>
#include <stdio.h>
#include <time.h>

/**
 * Find the largest time_t for which ctime returns a non-NULL value
 * using a bsearch between 0 and LONG_MAX.
 **/
static time_t ctime_max() {
    time_t start = 0, end = LONG_MAX, mid;
    while (start < end) {
        mid = start + (end - start) / 2;
        if (ctime(&mid)) {
            /* this mid is ctime-able; try higher */
            start = mid + 1;
        } else {
            /* this mid is not ctime-able; try lower */
            end = mid;
        }
    }
    /* mid is now the lowest number that's too high; subtract one */
    return mid - 1;
}

int main() {
    time_t t = ctime_max();
    printf("%s", ctime(&t));
    return 0;
}

For me that comes out to Tue Dec 31 23:59:59 2147483647 which happens to be the second before the year overflows four signed bytes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top