4 ms·
Personally this[1] just makes C much more complicated for me, and I choose C when I want simplicity. If I want complicated, I would just pick C++ which I typica
by johnisgood 2y ago
Personally this[1] just makes C much more complicated for me, and I choose C when I want simplicity. If I want complicated, I would just pick C++ which I typically would never want. I would just pick Go (or Elixir if I want a server).
"_BitInt(N)" is also ugly, reminds me of "_Bool" which is thankfully "bool" now.
[1] guard, defer, auto, constexpr, nullptr (what is wrong with NULL?), etc. On top of that "constexpr" and "nullptr" just reeks of C++.
That said, Modern C is an incredible book, I have been using it for C99 (which I intend to continue sticking to).
- cornstalks 2y ago> what is wrong with NULL? For starters, you have to #include a header to use it.
- zik 2y agoAnd it avoids the NULL == 0 ambiguity, allowing for better type checking.
- johnisgood 2y agoWell, I always include stdio.h which includes stddef.h that defines NULL as (void *)0.
- dhhfss 2y agoIn my experience, hardly any source files require studio.h stddef.h on the other hand is required by most to get size_t
- johnisgood 2y agoYou are right. Hereby I correct my parent comment: I talked about my own personal experience[1], but yeah, as you said, stddef.h is often required (and yes, often I do not need stdio.h, stddef.h is what I need) which defines NULL, which was my point. If it is often required, then it does not matter whether you have to include a header file or not, IMO. Just include the stddef.h header if you want to use NULL, similarly to how you include a header file if you want to use anything else, e.g. bool from stdbool.h. [1] I am not entirely sure in retrospect, actually, as I might be misremembering, but my point stands with or without stdio.h!
- deleted 2y ago[deleted]
- mmphosis 2y agoNULL is not wrong. The things that I will do with NULL are
- deleted 2y ago[deleted]
- deleted 2y ago[deleted]
- nickelpro 2y ago> what is wrong with NULL? One of the few advantages of ISO standardization is you can just read the associated papers to answer questions like this: https://wg21.link/p2312 https://wg21.link/p2312 The quick bullet points: * Surprises when invoking a type-generic macro with a NULL argument. * Conditional expressions such as (1 ? 0 : NULL) and (1 ? 1 : NULL) have different status depending how NULL is defined * A NULL argument that is passed to a va_arg function that expects a pointer can have severe consequences. On many architectures nowadays int and void* have different size, and so if NULL is just 0, a wrongly sized argument is passed to the function.
- deleted 2y ago[deleted]
- flohofwoe 2y agoauto is mostly useful when tinkering with type-generic macros, but shouldn't be used in regular code (e.g. please no 'almost always auto' madness like it was popular in the C++ world for a little while). Unfortunately there are also slight differences between compilers (IIRC Clang implements a C++ style auto, while GCC implements a C style auto, which has subtle differences for 'auto pointers' - not sure if those differences have been fixed in the meantime). _BitInt(N) isn't typically used directly but typedef'ed to the width you need, e.g. typedef _BitInt(2) u2; The 'ugly' _B syntax is needed because the combination of underscore followed by a capital letter is reserved in the C standard to avoid collisions with existing code for every little thing added to the language (same reason why it was called _Bool). AFAIK defer didn't actually make it into C23? I'm also more on the conservative side when it comes to adding features to the C standard, but IMHO each of the C23 additions makes sense.
- humanrebar 2y ago> IIRC Clang implements a C++ style auto, while GCC implements a C style auto, which has subtle differences for 'auto pointers' - not sure if those differences have been fixed in the meantime Both have compatibly implemented the standard C++ auto. Since 2011 or so.
- flohofwoe 2y agoWell, not in C :) Here's an example where Clang and GCC don't agree about the behaviour of auto in C23: https://www.godbolt.org/z/WchMK18vx https://www.godbolt.org/z/WchMK18vx IIRC Clang implements 'C++ semantics' for C23 auto, while GCC doesn't. Last time I brought that up it turned out that both behaviours are 'standard compliant', because the C23 standard explicitly allows such differing behaviour (it basically standardized the status quo even if different compilers disagreed about auto semantics in C). PS: at least Clang has a warning now in pedantic mode: https://www.godbolt.org/z/ovj5r4axn https://www.godbolt.org/z/ovj5r4axn
- johnisgood 2y agoThis difference of implementation in two of the major C compilers leaves a bad taste in my mouth. :/
- deleted 2y ago[deleted]
- josefx 2y ago> (what is wrong with NULL?) The old definition did not even specify wether it was a pointer or an integer. So for platforms that did not follow the Posix ((void*)0) requirement it was a foot gun that had neither the type nor the size of a pointer. > On top of that "constexpr" and "nullptr" just reeks of C++. Probably because they where back ported from C++. You can still use NULL, since that was apparently redefined to be nullptr.
- johnisgood 2y agoWhat platforms are those that are in use, and how widespread their use is?
- consteval 2y ago> If I want complicated, I would just pick C++ which I typically would never want In my opinion, complexity doesn't scale linearly like this. Sometimes, in fact often times, having more complex tools means a simpler process and end result. It's like building a house. A hammer and screwdriver are very simple. A crane is extremely complex. But which simplifies building a house? A crane. If I wanted to build a house with only a hammer and screwdriver, I would have to devise incredibly complex processes to get it done. You see the same type of thing in programming languages. Making a generic container in C++ is trivial. It's very, very hard in C. You can make it kind of generic. You can use void * and do a bunch of manual casting. But it's cumbersome, error prone, and the code is more complex. It's counter-intuitive - how can C, a simpler language, produce code that is more complex than C++? Or look at std::sort vs qsort. The power of templates and functors makes the implementation much simpler - and faster! We don't have to pass around void * and dereference them at runtime, instead we can build in comparison into the definition of the function itself. No redirection, no passing on the stack, and we can even go so far as to inline the comparison function. There's really lots of examples of this kind of stuff. Point being, language complexity does not imply implementation complexity.
- swells34 2y agoIn my experience, complex tools encourage fluffy programming. You mention a generic container; if I were using C, I just wouldn't use a generic container; instead, I'd specify a few container types that handle what needs handled. If there seem to be too many types, then I immediately start thinking that I'm going down a bad architecture path, using too many, or too mixed, abstraction layers, or that I haven't broken down the problem correctly or fully. The constraints of the tool are inherited in the program; if the constraints encourage better design, then the program will have a better design. You benefit from the language providing a path of least resistance that forces intentionality. That intentionality makes the code easier to reason about, and less likely to contain bugs. You do pay for this by writing more boilerplate, and by occasionally having to do some dirty things with void pointers; but these will be the exception to the rule, and you'll focus on them more since they are so odd.
- 2y ago
- jlokier 2y ago> what is wrong with NULL? This code has a bug, and may even crash on some architectures: execlp("echo", "echo", "Hello, world!", NULL); This code doesn't have the bug: execlp("echo", "echo", "Hello, world!", nullptr); Neither does this: execlp("echo", "echo", "Hello, world!", (char *)NULL);