Hacker News new | ask | show | jobs
by LucaSas 2387 days ago
Hi, thanks for your feedback. I am the original author.

Regarding prefixes, I advice that you start by writing the library in C and then wrap it in C++ for a variety of reasons that you might want to consider. In C++ you should indeed always use namespace.

Header guards have the advantage over pragma once that they are standard and you can also use them to check if a library is included. I might remove that since maybe it's not that important and people might different views.

Regarding constants, I was referring to things such as numeric constants for which you would constexpr in C++. Maybe I can be more explicit there. Thanks for the feedback.

1 comments

I advise you start by writing the library in C++ and then wrap it in C if you need C ABI of the library.

It’s very hard to write correct C code which does IO and supports multithreading. Take a look at Microsoft’s implementation of fprintf, copy-pasted from Windows 10 SDK: https://gist.github.com/Const-me/f1bb320969adde6c79694265ea6... They use RAII to set & revert the locale, and to lock RAM buffer to avoid corruption by another threads. They use C++ lambda for exception handling. They even use C++ template to avoid code duplication between printf and wprintf.

But these C++ shenanigans are not exposed to user, user calls their `printf` (possibly in a code built by C compiler) and it just works.

> It’s very hard to write correct C code which does IO and supports multithreading

This is just a random unsubstantiated statement. There's nothing particularly "hard" about writing IO libraries that is language-specific. Multithreaded or not.

When you do IO and multithreading, functions often need to acquire and release stuff: mutexes or other locks, resources, locales. Even more so in videogames, e.g. OpenGL code often calls glMapBuffer / glUnmapBuffer many thousand times each frame.

The hard part is making sure you release stuff every time you acquire stuff, exactly once. C++ RAII makes it almost trivially simple, but standard C has nothing comparable. When you only targeting gcc and clang can use __attribute__(cleanup) in C, it helps but still it’s more limited and more error prone compared to destructors.

> The * hard part * is making sure you release stuff every time, exactly once.

Oy vey... you can't be serious. That's rudimentary basics of using any API.

It’s easy enough to correctly use a small API in a small program. It doesn’t matter at all for short-living apps which clean up their resources by exiting the process.

There’re also other programs in wide use, which need to reliably work for hours, sometimes weeks. Some of them have huge amount of code they built from, written by many people over many years. Combine that with large enough APIs (some peripheral devices have hundreds of writeable registers of state; or D3D11 exposes huge amount of very complicated state, only limited by VRAM amount which is measured in gigabytes) and it’s very easy to make bugs in such programs.

Leaks of memory, handles, sockets, and many other resource types e.g. GPU ones. Deadlocks caused by locked mutexes, or threads which exit but forgot to release something they needed to release. Unwanted changes to global or thread state, both internal to the process and external (locales, formatting options, console colors, process and thread priorities, current directory, environment variables, CPU registers like FPU flags and interrupt masks, GPU render states) caused by some code changing stuff but not reverting the changes back. Unwanted state changes of custom peripheral devices, due to the same reason.

C++ RAII is not a silver bullet, but it does help a lot for all these things.

It's easy enough to implement correct API usage semantics in a program of any size.

If you need to rely on RAII in order not to screw things up, then it's an issue with the coding style or the application design. That's what needs fixing. Not the language choice. You got it backwards.