Imagine you just called time(2) and got a time_t value. Something like:
time_t asdf = time();
And now you want to use printf to print that value to the screen. You can cast to 'long long', which is guaranteed to be at at least 64 bits wide, and ensure no loss of precision occurs:
printf("%lld", (long long)asdf);
That will work whether time_t is 32 bit or 64 bit.
"short", "long", "long long" are all non-sensical. You use them when you want to trade size and range. When you want to make that trade-off, you care what their sizes are.
Instead of lower/upper bounds on their sizes, which aren't very useful, they should just have specific sizes. At which point, you might as well use uint32_t, and uint64_t in place of long and long long.
Prefer the sized int types over the "long"/"long long" ones when you can, for saner coding.
Use uintptr_t and such when you need a ptr-sized int, rather than a specific size.
You need to realize that the size of most types in C have been perverted by history. When possible, it's best to use the few types that are unambiguous in all of C89, LLP64 and LP64.
> int64_t is a much nicer type than "long long".
Yes, except that "long long" has been part of the standard for longer. in64_t was part of C99 but is tricky to include in software up to the mid 2000's due to slow adoption of the standard.
You can use "long long" without headers in most C compilers from the last 20 years. int64_t when present is usually just a typedef to "long long". Keep it simple.
> "int" makes some sense. Word-size of the machine.
Except that it isn't. That was its original intent but for historical reasons, it is a 32 bit integer in almost all cases now, regardless of machine word size.
I fail to see why it's more reasonable to prefer "long long" to "int64_t" just because the former existed for longer. It's not year 2000 today and C99's not a hot new thing not many compilers support. Or OpenBSD do have some policy that their kernel must be able to build with any C89-compliant compiler?
It's not the kernel that's the issue, we're talking about basic, cross-platform userland utilities like "ping" here. Some of those do have a policy that they have to be able to build on Irix 5.8 or whatever.
Is there anything that forbids those utilities from using system-provided headers and time_t? I think they'll build fine on any POSIX.1-compliant system then.
Unless they're doing something really weird with time_t values, I don't think there's any reason they should know whenever it's long long or int64_t or whatever under the hood.
Why cast to `int64_t` here? Just because `time_t` could be `int64_t` under the hood doesn't mean it must be casted to this exact type for string formatting/presentation purposes.
And I thought `%lld` actually means `long long`... So, http://ideone.com/SJJFPs seems like a proper approach to me. That said, if compiler supports %lld (an %I64d or alike might be required for older compilers), so a better cross-compiler approach would be in lines of `printf("test: " TIME_FMT "\n", (TIME_FMT_CAST)t)`. Or, ahem, maybe, `print_time(t)`.
Assuming we don't want to maintain a set of per-platform macros, we need to use an existing, standard format specifier. There isn't one that takes a time_t. So we have to cast time_t to a type big enough to contain it, use the format specifier for that type, and we want this to be as cross-platform as possible, i.e. we use the oldest, most widely-supported type which can definitely hold at least 64 bits and has a standard printf specifier available. i.e. "long long", exactly as in your example code.
So that's why we prefer "long long" rather than "int64_t", which I thought was your original question.
Oh. I thought the discussion was not about what type to cast when using printf (I agree, only `%lld`/`long long` fits perfectly), but what type to use for `time_t` internally. Sorry if I misunderstood and missed the point.
Please don't be disingenuous. We both know that using #defines, you can get a type which is exactly 64 bits on any modern architecture. The fact that long long and long int are a builtin types and int64_t is implemented in terms of them, rather than the other way around, is just an implementation detail.
<time.h> is userspace. It's at least theoretically possible for long long to be more than 64 bits. Why use long long (potentially, say, 128 bits) rather than int64_t for time_t?
And why wouldn't int64_t be available in kernel space?
I always found this special-casing of headers for kernel vs user unnecessary and complicating. In the many embedded runtimes I maintain, I've moved towards using standard POSIX-y and C(++) standard headers everywhere. I know kernel folks love to believe that their world is special so all the usual C library stuff needs to be done differently, but it's not needed.
It's so much easier to port code between the two worlds when you don't have to litter the #include prelude of every C file with conditionals.
A few times I got flamed on this site for complaining that the average HNer can't have reasonable discussions about C. I think the comment that the OpenBSD team should just #include <linux/types.h> pretty well shows that I was right. :-)
I'm not familiar with the OpenBSD kernel. Is there any good reason (for OpenBSD or any other kernel) why <stdint.h> shouldn't be available -- or at least why int64_t shouldn't be available in some header?