[HN Gopher] Rethinking the C Time API
___________________________________________________________________
Rethinking the C Time API
Author : oliverkwebb
Score : 61 points
Date : 2025-02-16 14:26 UTC (8 hours ago)
(HTM) web link (oliverkwebb.github.io)
(TXT) w3m dump (oliverkwebb.github.io)
| tempodox wrote:
| The author could use a lesson in visual design.
|
| https://www.contrastrebellion.com
| grg0 wrote:
| Good resource.
|
| The way I fix bad websites is by telling Firefox not to load
| external fonts and font styles.
| turtleyacht wrote:
| Updated link to referenced work _Time, Clock, and Calendar
| Programming in C:_
|
| http://www.catb.org/esr/time-programming/
| oliverkwebb wrote:
| Thanks, the link esr provides in his website
| (https://www.catb.org/~esr/faqs/time-programming/index.html)
| leads to a 404
| mjburgess wrote:
| 95% of the supposed issues with C could be solved by a new
| standard library, integrating the debugger into the compiler as
| the default build/run environment (with auto address
| sanitisation, frame protection, etc. etc.), and a default strict
| mode error checking.
|
| It would then be actually really hard to successfully run a C
| program (in the debugger) with any problems. Under these
| conditions it'd be easy to imagine most C programs running with
| fewer bugs (, leaks, etc.) than Rust programs.
| pjmlp wrote:
| Except it is easier to introduce a new programming language
| than having a committee driven language to adopt a new standard
| library.
|
| Neither ISO nor OpenGroup would care about it.
|
| Remember that since 1989, no actions were taken to improve its
| security.
|
| Even the few functions that have been added still use
| pointer/length pairs without any means to validate they are the
| correct pair.
| Someone wrote:
| > Remember that since 1989, no actions were taken to improve
| its security.
|
| Not much, but not nothing, either. _gets_ was deprecated in
| C99 and removed in C11
| (https://en.wikipedia.org/wiki/C_file_input/output#gets)
| pjmlp wrote:
| Yet the scanf and fgets possible exploits are still there.
| rdpintqogeogsaa wrote:
| > Remember that since 1989, no actions were taken to improve
| its security.
|
| Technically, gets() was removed from the standard library in
| C11[0]. However, that is far from a semantically meaningful
| overhaul of the standard library. I nonetheless felt the need
| to point out that there was a very specific effort for the
| sake of completeness.
|
| [0] https://en.cppreference.com/w/c/io/gets
| pjmlp wrote:
| Which is great, except for all those stubborn folks not
| using anything beyond C99, and scanf and fgets are still
| possible attack vectors, when getting sizes wrong.
| ctoshiningc wrote:
| Have you tried talking to them?
| nine_k wrote:
| Create a language with semantics exactly like C, but the
| standard library completely replaced. Call it in a way that
| avoids trademark disputes (e.g. CWSL, C With Sane Library).
| Get GCC and LLVM support it, which should be reasonably easy,
| because both support compiling code that does not rely on
| libc (though OS entry point code, etc should be wired in).
|
| Would it be easy enough to port important C code to it, given
| that most of the libc-supplied functions, and functions
| transitively depending on these, would have to be rewritten?
| Would it be worthwhile, compared to rewriting such code it in
| Zig, Rust, or Ada?
| pjmlp wrote:
| There have been multiple attempts at this, how many folks
| heard of Safe-C, C3,... ?
|
| Only bothering to list two examples, there are many others,
| even Cyclone is partially C compatible, guess what came out
| of Cyclone.
| oguz-ismail wrote:
| >Safe-C
|
| import statements are a deal breaker
|
| >C3
|
| shit syntax
|
| >Cyclone
|
| vaporware
| MyOutfitIsVague wrote:
| Why in the world would import statements be a deal
| breaker?
| oguz-ismail wrote:
| > The .h and .c files of a component must always be
| stored in the same folder so that the compiler can find
| them
| pjmlp wrote:
| Learn to use your compiler switches.
| shakna wrote:
| D began life as a re-engineered C++. (I'm sure Walter will
| correct me if I say any more).
|
| There's a Safe C++ extension proposed for Clang [0].
|
| But those are C++, not C. A little different kettle of
| fish.
|
| Gnome's Vala [1] aims to be the "smoothest C off-ramp". It
| does compile to C, but with GObject taking control of
| everything.
|
| There's CheckedC [2], which adds optional bounds checking
| to C, and was backed by Microsoft until recently.
|
| There's the Linux kernel's nolibc [3], which I've enjoyed
| the heck out of using, but it is rather constrained.
|
| There's C's own Annex K [4], that almost nobody has
| implemented, and every compiler developer hates and can
| poke holes in. GCC and LLVM have both repeatedly said they
| won't support it. (So much as easy to get them to support
| things...)
|
| GCC already has a number of memory safe languages, though.
| Most of which, because they're part of the same compiler
| suite, can interact with other languages that GCC has. Like
| the D or Go frontends.
|
| [0] https://discourse.llvm.org/t/rfc-a-clangir-based-
| safe-c/8324...
|
| [1] https://vala.dev/
|
| [2] https://www.checkedc.org/
|
| [3] https://lwn.net/Articles/920158/
|
| [4] https://www.open-
| std.org/jtc1/sc22/wg14/www/docs/n1106.txt
| chrsig wrote:
| eh, i think i disagree. a new stdlib on its own wouldn't come
| with a lot of abi/linking baggage that tends to hold up
| tooling and migrations when you start introducing a different
| language. (see recent rust/linux drama).
|
| i mean, if the committee members can make it happen or not, i
| don't know. but it's still a worthy thing to explore, I
| think. there's going to be a lot of C code that will need a
| very gradual migration path to safer apis for a very very
| long time.
| Keyframe wrote:
| might as well throw in MISRA-C checker into it.
| oliverkwebb wrote:
| The core of C is pointer arithmetic; This creates a
| fundamentally unsafe environment.
|
| You can't even do anything in C without some asm (syscall
| wrappers) because C was meant to boil down and streamline
| PDP-11 assembly (Your computer is not a fast PDP-11) to a set
| of consistent principles. The consequence of this is that the
| core of the language is pointers and pointer arithmetic, and
| raw unabstracted pointers are fundamentally unsafe to work
| with.
|
| Using the rust type system I can essentially confirm code is
| bug and edge-case free with exhaustive matching and unit
| testing (C's lack of tooling blessed the world with autoconf
| and cmake btw). Not to mention rusts ability to abstract away
| necessary boilerplate gives me more time to think about my code
| instead of pointer arithmetic and allocation heuristics.
|
| The "cure" for C is a language that abstracts away raw pointers
| and memory allocation.
| oguz-ismail wrote:
| > You can't even do anything in C without some asm (syscall
| wrappers)
|
| Which language can do anything without some asm and support
| as many platforms as C?
| oliverkwebb wrote:
| > Which language can do anything without some asm and
| support as many platforms as C?
|
| I wouldn't be surprised if someone figured out how to do
| the interrupts and register control necessary to invoke
| syscalls with pure LISP/Scheme/CL :P
|
| P.S. anything that compiles with LLVM and has an ingrained
| way to do print() that doesn't invoke libc, although
| there's a blurry line here between "pure asm"/"compiles to
| asm" that involves trusting-trust-style bootstrapping of
| features into the compiler
| oguz-ismail wrote:
| You don't know what you're talking about
| nolist_policy wrote:
| > > Which language can do anything without some asm and
| support as many platforms as C?
|
| > I wouldn't be surprised if someone figured out how to
| do the interrupts and register control necessary to
| invoke syscalls with pure LISP/Scheme/CL :P
|
| Haha
|
| > P.S. anything that compiles with LLVM and has an
| ingrained way to do print() that doesn't invoke libc,
| although there's a blurry line here between "pure
| asm"/"compiles to asm" that involves trusting-trust-style
| bootstrapping of features into the compiler
|
| Actually LLVM IR has no concept of syscalls, you have to
| use inline assembly inside your IR to issue syscalls.
| kazinator wrote:
| What haha; we had that decades ago: systems programmed in
| Lisp from the bare metal.
|
| Here is what assembly code looks like in (ccl) Clozure
| Common Lisp:
|
| https://github.com/Clozure/ccl/blob/master/level-0/X86/x8
| 6-h...
|
| ARM version of same file:
|
| https://github.com/Clozure/ccl/blob/master/level-0/ARM/ar
| m-h...
| mjburgess wrote:
| You can write every program you want to without pointer
| arithmetic.
|
| If you mean that a dereference of a memory location involves
| the compiler emitting pointer arithmetic instructions --
| that's true of all languages.
|
| If you want your language to completely disguise the machine
| from you, and "abstract away" memory allocation, you're going
| to pay a high complexity cost to do so.
|
| If you have never run C in a debugger, with the massive
| amount of highly sophisticated tooling available to C
| debuggers, then you're operating from a profoundly mistaken
| starting point for evaluating the viability of C for modern
| safe sofware development.
|
| C debuggers and tooling are vastly more powerful than Rust's
| static type system, and catch a much wider array of memory
| problems (, and bugs) than the Rust compiler can catch.
| Static verification is far more limited than the dynamic
| verification a sophisticated debugger can perform.
|
| People's undergrad C course is a terrible basis on which to
| evaluate what C is today. The reason C is associated with a
| lack of security is that almost all software is written in C,
| written in a time when either the internet didnt exist or
| didnt imply an adversarial _local_ environment.
|
| Running a network cable through every facet of our O/S and
| software breaks many assumptions about the entire history of
| programming -- which C predominated in. This is a very poor
| basis on which to generalize the capabilities of a well-
| specified C programming environment (which today, is much
| more powerful than Rust's compiler).
| mschuster91 wrote:
| > People's undergrad C course is a terrible basis on which
| to evaluate what C is today. The reason C is associated
| with a lack of security is that almost all software is
| written in C, written in a time when either the internet
| didnt exist or didnt imply an adversarial local
| environment.
|
| The problem is - undergrad C is about the lowest common
| denominator that all tooling understands and that _all
| people_ understand. Of course you 're probably not going to
| have to go as low as C89 like sqlite or, until 2022, the
| Linux kernel [1], but still, the long support cycles of
| many distributions make it challenging to move standards
| upgrades forward.
|
| [1] https://www.zdnet.com/article/linus-torvalds-prepares-
| to-mov...
| LegionMammal978 wrote:
| > C debuggers and tooling are vastly more powerful than
| Rust's static type system, and catch a much wider array of
| memory problems (, and bugs) than the Rust compiler can
| catch. Static verification is far more limited than the
| dynamic verification a sophisticated debugger can perform.
|
| Is there any dynamic verifier that fully validates all
| acesses w.r.t. the object trees specified by the C
| standard? Tools like ASan and UBSan won't detect a write to
| one field running into another field, only a write
| overrunning the complete object. (Compiler-level hardening
| might catch that to some extent, but it's limited to TU
| boundaries.) Not to mention things like 'misuse of restrict
| pointers' that I've never seen any verifiers for, except
| for special cases like overlapping memcpy() buffers.
|
| Meanwhile, Rust does have its own dynamic verifier, called
| Miri [0], which checks just about every language-level rule
| at runtime. The main drawbacks are that it's slow and
| doesn't support calling arbitrary C functions, but it would
| be hard to get that to work short of the Valgrind route of
| emulating the whole process on an instruction level.
|
| [0] https://github.com/rust-lang/miri
| mjburgess wrote:
| If you're redoing the c std, which was my initial point,
| you can introduce a debug allocator with metadata about
| object layout. Coupled with some debugger support, i'd
| imagine you can get there. And if the C std was willing
| to allow constexpr to do more at compile time, you
| wouldn't need explicit debugger support and could just
| use constexpr to modify the compiler.
|
| There's also nothing stopping debuggers reifying the C at
| debug-time into this metadata.
|
| My claim is 95% can be fixed by just normalizing what is
| current practice at the stdlib level and compiler level.
| By extending constexpr, i think you could get to 100%.
| Given that this is the case, why even both with the
| nightmare of Rust.
| LegionMammal978 wrote:
| Oh, you sounded like you were talking about something
| that already exists today, rather than something that
| you'd like to exist. The main problem with taking dynamic
| verification all the way is making it work with ABI
| boundaries, which won't be going anywhere in at least the
| next decade. You'd need everyone to migrate to a
| universal ABI that can convey all needed metadata, and
| while I've seen a few proposals for that, none of them
| have gone anywhere.
| mjburgess wrote:
| I was more saying that the scope of issues mainstream
| tooling catches, includes ones that the rust compiler
| doesn't catch, and many more than enough for what are
| common memory safety issues -- there are some issues that
| aren't caught, sure -- but the operations which can cause
| those bugs are well-defined, most programs wouldnt have
| to use them, and a new std lib would help.
|
| When people propagandize about C, they're universally
| unaware that the normal process of development basically
| addresses most of the problems Rust is supposed to be
| solving, and more than the rust compiler alone solves.
| The remainder are 95% to do with libc, which should just
| be thrown out.
|
| A smidge more compile-time eval with constexpr, and the
| use case for Rust could disappear. It's a great shame
| that C is run by a standards process that's determined to
| relegate it to electric motors and digital watches from
| the 80s.
| jcranmer wrote:
| > C debuggers and tooling are vastly more powerful than
| Rust's static type system
|
| As someone who's worked on C debuggers and tooling... I
| really have no idea what you're talking about. C's core
| semantics are just so weak that it's not really possible to
| express a lot of the things you can express in the type
| system, and that's before we get to the necessary lossiness
| that debuggers and tooling have to work with (e.g., you
| can't just ascribe types to memory in C because C--in
| practice--is way too loose with types for that to be
| meaningful).
|
| For an example from something I've worked on, Linux manages
| to have two different arrays for the GPRs for a thread
| register context, one that's used for ptrace and one that's
| used for signal contexts. Helpfully, the header files give
| you macros to map register names to numbers so that you can
| say regs[RAX] instead of regs[0]. But the offsets are
| different, so you have to remember that you need to use
| regs[REG_RAX] instead of regs[RAX], and there is absolutely
| no tooling in the world that can tell you when you get it
| wrong because there is no expressible difference between
| the two scenarios in C. Meanwhile, in Rust, I can wrap the
| accessors in newtypes so that I can _only_ use the correct
| set of constants to index into the array, which makes the
| error state literally impossible to construct.
|
| That's the real value of a static type system--you can use
| it to make errors _literally impossible_ to specify in an
| API.
| mjburgess wrote:
| I don't see the difference between having a typed access
| API (V inline reg_at(enum K k) {} ) and overloading the
| indexer.
|
| If your point is that historical C APIs have overused an
| untyped operation, that's part of my point about a new
| std lib. Rust APIs can still provide an untyped indexer,
| it's just bad API design.
|
| What I'm imagining a new std lib would be doing is having
| debug allocators, metadata against types, etc. Ie., a std
| library designed for the debugger along with a release
| version.
| jcranmer wrote:
| Using different enums doesn't help, because C will
| happily let you cast enum A to enum B implicity.
|
| In Rust, I _can_ express an API which can 't be used
| incorrectly. In C, I _can 't_. Sometimes, in C, you can
| _sometimes_ get to the point where you use conventions
| that means maybe static or dynamic analysis tools _might_
| be able to flag the misuse of the API, but very often,
| such tools have extremely poor tradeoffs between
| precision and accuracy, far worse than exists in Rust
| with just the vanilla compiler.
| mjburgess wrote:
| -Wconversion , no?
|
| My point isn't that you exhaust all the features of Rust
| with a better stdlib and "debugger-oriented programming"
| -- my point is that you can get 95% of the way there with
| trivial complexity costs.
|
| Rust imposes significant program design costs which can
| be very detrimental to otherwise trivial performant
| memory management, to faster iteration of software
| design, and so on. These aren't free lang. features.
| ctoshiningc wrote:
| The Rust Evangelism Strike Force clearly hasn't been defunded
| by DOGE (yet). Respectfully, if you want to use Rust, just use
| Rust. If C doesn't suit you, you don't have to use it, and you
| don't have to make unreasonable demands of the standards body.
| josephg wrote:
| I think this is a really good idea, and zig shows how it could
| work.
|
| But this?
|
| > Under these conditions it'd be easy to imagine most C
| programs running with fewer bugs (, leaks, etc.) than Rust
| programs.
|
| This is a crazy goal. You will never out-rust rust by adding a
| few runtime checks to C, while in debug mode. Fewer bugs than
| rust code is a wild goal.
|
| I don't think you understand just how much rust's design
| prevents you from shipping bugs. It's due to a combination of
| so, so many things. Like: references instead of pointers,
| unsafe blocks, sum types & match instead of unions, no implicit
| nullability, unwrapping optional values is explicit, the result
| type and #[must_use], bounds checks, the borrow checker
| preventing use after free, ownership semantics, Send & Sync for
| thread safety, and I'm sure plenty more.
|
| It's common to write very complex, threaded rust code and have
| it work first time. Well, the first time it compiles. Coming
| from C, it's wild. Or, really, just about any other language.
|
| To get the same result in C wouldn't just need a "strict mode".
| You would need to ban raw pointers - which would make it no
| longer C. And you'd need to make functions return more than an
| (easily ignored) status code. Ie, you want a result type. For
| bounds checking, you'd need a language level data structure for
| slices / arrays (pointer + length). You'd have to do away with
| void pointers for "generic" parameters. And probably 100 other
| tiny, breaking changes that the C community will never accept.
|
| And for all that, you would essentially get zig. Zig does all
| these things.
|
| But that would still get you worse bug density than rust
| because you don't have a borrow checker. It'll get you close -
| Runtime checks in debug mode will detect your use after frees -
| if you have a good test suite. But they won't prevent aliasing.
| Or (I think) help with thread safety. For that, you need a
| borrow checker. You need rust.
| shakna wrote:
| > strftime() has to write to a string of a fixed length it can
| not dynamically allocate (This is less legacy than it is bad
| design)
|
| There's good reason for this. I disagree that it's a bad design.
|
| strftime can legitimately produce zero-length strings, in a non-
| error state. You do not want an allocation on the heap, that is
| empty.
|
| You'd end up with more error states to track, and more confusion
| around whether the function had succeeded. (Especially when using
| %c).
| CamperBob2 wrote:
| A zero-length C string is still one byte long, for better or
| for worse.
| shakna wrote:
| Right. So you have an extra byte you need to free. One that
| you can't introspect, and reading will cause a memory fault,
| because it won't be NULL-terminated (0-length means 0
| length). And not freeing, because the assumption of 0-length
| is violated, leads to a memory leak.
|
| So instead of just checking one return value, now you have to
| check two. And people are not great at even handling a single
| NULL check. Few people check malloc's return, as awful as
| that is.
|
| Design should be intuitive as possible. You can't assume
| they'll even look at a manpage.
|
| If something returns a length, then people assume that length
| is what will be allocated. A valid 0-length time string,
| violates that assumption, and will cause problems down the
| line.
|
| If someone is forced to do the allocation themselves, then
| there's a greater chance they'll actually notice that they
| need to free it.
| CamperBob2 wrote:
| What? No, the null terminator _is_ the single byte in
| question. That 's how an empty string is represented in C.
| It's not the same thing as a NULL pointer, as you may be
| thinking.
| mastax wrote:
| I wasn't aware that on non-x86 platforms long double is often
| implemented with quadruple precision. I had assumed it was an
| x87-specific hack. On ARM64 windows/macos long double is
| apparently 64-bits which could be a problem.
|
| Personally something about that solution is unsatisfying. Feels
| like it'd be slow, even though that wouldn't matter 95% of the
| time. I'd rather have 128-bit integer of nanoseconds.
|
| https://en.wikipedia.org/wiki/Long_double
| immibis wrote:
| The requirements for time in computers have increased drastically
| since C was invented.
|
| Time used to mean what we write down or see on a clock:
| 2024-08-13 02:27 PM. The computer had an electronic clock built
| in, so it could save you a little effort of looking at the clock
| and copying the numbers. And that was all it did. If your clock
| was a few minutes off, that was no big deal. People knew clocks
| only agreed to within one or two minutes. People knew clocks were
| different in far away lands. Some people knew that you have to
| adjust your clocks twice per year. The computer clock was just
| like any other clock but happened to be inside a computer.
|
| Now we expect a globally synchronized unique identifier for each
| instant, regardless of timezone. This is hard to deliver.
| Computers use these for synchronization amongst themselves, so
| they have to be accurate to milliseconds or better. This is hard
| to deliver. We expect computers to handle requests from far away
| lands with as much grace as requests from the local operator, and
| deliver results in a format the people in those lands expect.
| This is hard to deliver. We expect computers to process requests
| about the past using information that was current in the past,
| all over the world. This is hard to deliver. We expect computers
| to automatically adjust their own clocks twice a year, not just
| on the dates everyone in your local area does, but for users in
| all parts of the world on their respective dates. This is hard to
| deliver. And we still haven't got graceful handling of completely
| different calendar systems.
| Gibbon1 wrote:
| Interesting thing about hardware real time clocks. They are
| usually as bad as the C time API.
|
| I worked with a guy that designed three RTC clock cards for an
| industrial bus system
|
| The first had registers for hours minutes, seconds, day, month,
| year. He was proud it handed the leap years correctly. It had a
| battery back up.
|
| The second design just had a 48 bit counter that counted ticks.
| You could read and and write it using latches so the
| read/writes were atomic.
|
| The third design was a read only 48 bit counter and a 1024 bit
| battery back ram.
|
| In the second and third design the conversion from time to a
| string is done in software. In the third the clock just
| provides a free running timer and you store an offset in
| battery backed ram along with other time related meta data.
|
| The vast majority of hardware RTC clocks today are implemented
| like the first example. It's a little infuriating since my
| coworker figured out how to do it right 45 years ago.
| ajross wrote:
| > Out of all the components of C, its time API is probably the
| one most plagued with legacy cruft.
|
| First off, no, locales and wide characters exist. This statement
| is just laughable.
|
| But even as to time: that seems really unfair. This whole area is
| a footgun and has been the source of bad implementation after bad
| implementation, in basically every environment. But among those:
| The "struct tm" interface is notable for being:
|
| 1. Very early, arriving in C89 and the first drafts of POSIX,
| with working implementations back into the mid 80's.
|
| 2. Complete and correct, able to give correct calendar
| information for arbitrary named time zones in an extensible and
| maintainable way. LOTS of other attempts got stuff like this
| wrong.
|
| 3. Relatively easy to use, with a straightfoward struct and a
| linear epoch value, with conversion functions in each direction,
| and only a few footguns (the mix of 0- and 1-indexing was
| unfortunate). There are even a few quality of life additions like
| support for "short" month names, etc...
|
| Really, these routines _remain useful even today_ , especially
| since their use is guaranteed to integrate with your distro's
| time zone database which must be constantly updated to track
| legal changes.
|
| There's stuff to complain about, but... no, I think the premise
| of the article is dead wrong.
| chrsig wrote:
| i don't read that as a condemnation of usefulness of
| integrating w/ the system tzdb (every language stdlib does this
| under the hood)
|
| my biggest issue is that the structs and function definitions
| are pretty opaquely named and make it very hard to learn let
| alone teach newcomers.
| ajross wrote:
| > 1. Very early, arriving in C89 and the first drafts of POSIX,
| with working implementations back into the mid 80's.
|
| I looked it up. In fact it's much earlier than that. The API
| arrived in time.h via v7 Unix in 1979.
|
| And it remains, unchanged, pervasively used, and most
| importantly _still used for new code_ , four and a half decades
| later. Rather than "legacy cruft", this constitutes one of the
| most successful utility APIs in human history.
| ctoshiningc wrote:
| I mean, this blog post is the kind of uneducated posturing that
| makes the JavaScript kiddies happy, because "crufty, old C is
| so bad, see!?". But none of them know enough to know that it's
| basically all bullshit.
| oliverkwebb wrote:
| Javascript is a famously cruft free language, as we all know.
|
| My real question is how you created an account, found this
| article, presumably read through it, and wrote out multiple
| comments insulting me all within two minutes.
| npalli wrote:
| Among the many improvements, time is one area where C++ has
| become better than old school C cruft. In c++20/std::chrono, the
| Lua like code is just this - auto now =
| system_clock::now(); zoned_time local_time{current_zone(),
| now}; std::cout << std::format("{:%a %b %d %T}\n",
| local_time);
| burntsushi wrote:
| Or Rust, with Jiff: println!("{}",
| jiff::Zoned::now().strftime("%a %b %d %T"));
| pjmlp wrote:
| Some C++23 flavour, :) auto now =
| system_clock::now(); zoned_time
| local_time{current_zone(), now}; std::println("{:%a %b %d
| %T}", local_time);
| bloak wrote:
| In an article like this I would have liked to see some mention of
| TAI (https://en.wikipedia.org/wiki/International_Atomic_Time) as
| one of the alternatives to UTC. Unfortunately there are several
| different universal times. Apparently there's also a "Galileo
| System Time", for example.
| asveikau wrote:
| I fail to see TFA's concerns or take them very seriously.
|
| > time() unnecessarily takes a pointer argument to write to
|
| Minor cosmetic issue.
|
| > strftime() has to write to a string of a fixed length it can
| not dynamically allocate (This is less legacy than it is bad
| design)
|
| This is often a good way to structure string functions in C. The
| fact that TFA repeated the constant 40 instead of using sizeof()
| immediately signals that they are unfamiliar with the idioms. A
| "you problem".
|
| Doing heap allocation where it is not required could be a problem
| for some use cases.
|
| > localtime() needs the pointer to a time_t value even though it
| does not change it because of register size concerns on PDP-11's
|
| Also minor and cosmetic.
|
| > sleep() cannot sleep for sub-second amounts of time, usleep()
| is deprecated and it's alternative nanosleep() requires you to
| define variables
|
| sleep(3) is not really a "time function" in the sense of the
| others mentioned, it is a thread scheduler function. As such it
| kind of exists in a different universe. This is also shown by the
| fact that it's part of POSIX and not the C standard, like time(2)
| is.
| ctoshiningc wrote:
| Another classic case of "if everyone does something differently
| than you do, it might be worth investigating why". The hubris
| to think that basic C time functions have been "broken" all
| this time, and that nobody noticed or cared. What a joke.
| oliverkwebb wrote:
| For a definition of "nobody" that includes Eric S Raymond,
| one of the most prominent figures in the linux world who's
| article (https://www.catb.org/esr/time-
| programming/index.html) I reference multiple times.
|
| [ _plonk_ ](https://www.catb.org/jargon/html/P/plonk.html)
| 1718627440 wrote:
| > Eric S Raymond [...] prominent figure[...] in the linux
| world
|
| Doesn't he work for Microsoft?
| oliverkwebb wrote:
| He was the publisher of the Halloween documents (from my
| understanding leaked by a whistleblower to him) and has
| always been a firm opponent to Windows in all his works.
| Are you thinking of Poettering?
| 1718627440 wrote:
| <del> Isn't this his blog:
| https://devblogs.microsoft.com/oldnewthing/ ?
|
| It is hosted by Microsoft and talks about implementation
| details of Windows. So I always assumed, that he works
| there.</del>
|
| My bad, that's Raymond Chen.
| forrestthewoods wrote:
| Many functions in the C API are quite badly designed. The
| hidden global state in locale for example. HN regularly has
| articles about nasty bugs that boil down to "C API has
| several major deficiencies that cause great pain and
| suffering.
| Joker_vD wrote:
| > keep in mind that Integers support One percision, and there's a
| trade off between resolution and the bounds of your epoch,
| Floating point values support all percisions, there is no such
| trade off.
|
| Yeah, except with integers you get guaranteed precision across
| all of your data range while with floating point, it is
| ridiculously easy to accidentally lose precision without noticing
| it when e.g. shifting time deltas from the past into the future.
|
| Not to mention that using floating-point number of seconds since
| epoch means that the times around the epoch are always given
| better precision than the timestamp around the current time which
| is really not what you want, and the situation only worsens with
| time.
| Animats wrote:
| Time parsing and formatting is prone to extended bikeshedding. I
| once raised the issue that Python had five parsers for ISO 8601
| date formats, and they were all broken in some way. It took a
| decade to resolve that. By then I'd moved on to Rust.
| atiedebee wrote:
| I don't think having strftime return a malloc'd pointer is a good
| idea. The string won't be large at all and can easily fit onto
| the stack (just like it was done in the example code). If I want
| to use a custom allocator to store the string, I can. If I want
| to malloc the string I can.
___________________________________________________________________
(page generated 2025-02-16 23:01 UTC)