• belter 2 hours ago

    Important reminder just in the Preface :-)

    Takeaway #1: "C and C++ are different: don’t mix them, and don’t mix them up"

    • jasode 44 minutes ago

      >Takeaway #1: "C and C++ are different: don’t mix them, and don’t mix them up"

      Where "mixing C/C++" is helpful:

      - I "mix C in with my C++" projects because "sqlite3.c" and ffmpeg source code is written C. C++ was designed to interoperate with C code. C++ code can seamlessly add #include "sqlite3.h" unchanged.

      - For my own code, I take advantage of "C++ being _mostly_ a superset of C" such as using old-style C printf in C++ instead of newer C++ cout.

      Where the "C is a totally different language from C++" perspective is helpful:

      - knowing that compilers can compile code in "C" or "C++" mode which has ramifications for name mangling which leads to "LINK unresolved symbol" errors.

      - knowing that C99 C23 has many exceptions to "C++ is a superset of C" : https://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B...

      • accelbred 31 minutes ago

        C++ can seamlessly include C89 headers.

        The C library headers for libraries I write often include C11/C99 stuff that is invalid in C++.

        Even when they are in C89, they are often incorrect to include without the include being in an `extern "C"`.

        • Conscat a minute ago

          Clang supports C11 - 23 in C++, as well as some future C features like fixed-point integers. The main pain points with Clang are just the fundamental differences like void* and char, which don't typically matter much at an interoperability layer.

          • nuancebydefault 20 minutes ago

            Extern "C" around the prototypes is mandatory, otherwise your linker will search for C++ symbols, which cannot be found in the C libraries you pass it.

        • pjmlp 2 hours ago

          Specially relevant to all those folks that insist on "Coding C with a C++ compiler", instead of safer language constructs, and standard library alternatives provided by C++ during the last decades.

          • flohofwoe an hour ago

            Funny because for a long time the Microsoft MSVC team explicitly recommended compiling C code with a C++ compiler because they couldn't be arsed to update their C frontend for over two decades (which thankfully has changed now) ;)

            https://herbsutter.com/2012/05/03/reader-qa-what-about-vc-an...

            • rdtsc an hour ago

              That thing always baffled me, this huge company building a professional IDE couldn't figure out how to ship updates to the C compiler.

              > it is hard to say no to you, and I’m sorry to say it. But we have to choose a focus, and our focus is to implement (the standard) and innovate (with extensions like everyone but which we also contribute for potential standardization) in C++.

              I mean, yeah if it came from a two member team at a startup, sure focus on C++, understandably. But Microsoft, what happened to "Developers! Developers! Developers!"?

              • Jtsummers 34 minutes ago

                It's not baffling, it's remarkably consistent. They implemented Java as J++ and made their version incompatible in various ways with the standard so it was harder to port your code away from J++ (and later J#). They implemented things in the CSS spec almost exactly opposite the specification to lock people into IE (the dominant browser, if you have to make your site work with 2+ incompatible systems which will you focus on?). Not supporting C effectively with their tools pushed developers towards their C++ implementation, creating more lock-in opportunities.

                • AlotOfReading 19 minutes ago

                  Funnily enough, the intellisense parser does support C syntax because it's using a commercial frontend by edison under the hood. MSVC's frontend doesn't.

              • com2kid 2 hours ago

                Perfectly valid to do if you need to interface with a large C code base and you just want to do some simple OO here and there. Especially if you cannot have runtime exceptions and the like.

                This is how I managed to sneak C++ into an embedded C codebase. We even created some templates for data structures that supported static allocation at compile time.

                • f1shy an hour ago

                  What would be an example of "simple OO here and there" that cannot be done cleanly in plain C?

                  • bobmcnamara an hour ago

                    Templating on pixel classes so that a blitter builds all supported pixel paths separately and inlines them.

                    Yes you can do it less cleanly with macros or inline functions. But you can't do it performantly with struct and function pointers.

                    • raluk an hour ago

                      RAII

                      • tjoff an hour ago

                        The killer feature of RAII is when combined with exceptions. But sneaking in exceptions in an embedded C project isn't something I'd encourage or recommend.

                        C++ imo doesn't offer anything compelling for the embedded usecase. Especially not considering all the footguns and politics it brings.

                        You can of course be strict and diligent about it but if you are you are pretty much just writing C anyway. Better to do it explicitly.

                        Allowing the use of the C++ standard library has been one of my biggest regrets (not that it was my decision to make, I fought it).

                        • f1shy an hour ago

                          Is RAII Object orientation? I thought it was an idiom of C++ by Stroustrup.

                          • runevault 18 minutes ago

                            It doesn't necessarily have to be OO no. Rust uses RAII and it uses traits instead of traditional OO style inheritance etc. You do need something like destructors/drop trait for it to work as far as I know though.

                        • cozzyd 17 minutes ago

                          CRTP?

                          • adamrezich an hour ago

                            Namespaces, methods.

                            • f1shy an hour ago

                              Namespaces is not object orientation, is it? Am I missing something? You can place functions (methods) inside of structs in C23, can't you?

                              • int_19h an hour ago

                                You can handcode vtables in C, just as you can handcode loops in assembly (i.e. it works but it's verbose, not particularly readable, and brings more footguns).

                                But why would you do that if you have an instrument that lets you work at the same level as C, but with methods provided as a proper abstraction that maps exactly to what you'd have written yourself anyway?

                                • staunton an hour ago

                                  On a high level, "object orientation" means you think of your code as representing the state and interactions of objects. You can equally well do this in assembly. If you think of some namespace as a "singleton object" then that's what it is.

                                  I guess what you're really asking is what are the best or most common ways to do OO in C?

                                  • f1shy an hour ago

                                    Oh. I learned that object orientation is primarily a way to structure data and code, such that the data is encapsulated with the code that works on it, in so called objects. So an Object is the Data, plus the functions that work on the data, an ensure that some invariants are kept. In OO parlance, that code gets executed by sending messages (calling methods).

                                    Where can I find something about objects being "think of your code as representing the state and interactions of objects" honesty totally new to me.

                                    So no, certainly I'm not asking ways to do OO in C. But it seems to be more definitions of object orientation as I thought...

                                    • epcoa an hour ago

                                      > Where can I find something about objects being "think of your code as representing the state and interactions of objects" honesty totally new to me.

                                      I’m scratching my head how you think this is materially different than what you described in your first para. s/state/data and s/interactions/methods.

                                      If anything though I would say the GP is more aligned with the classic definition as it highlights the focus is more on the messages (interactions) themselves rather than the implementation.

                                      • int_19h an hour ago

                                        There's no clear definition of what OO is, so the best you can do pragmatically is look at mainstream languages that are broadly recognized as OO and try to deduce the commonalities.

                                        If you do that, you'll notice that, for example, encapsulation is not a part of that de facto definition, because languages like Python and (until recently) JavaScript lack it, despite being considered OO.

                                        Indeed, the only two things that appear to be consistently present in all OO languages are: 1) some notion of object identity as distinct from object state, and 2) runtime polymorphic dispatch.

                                    • adamrezich an hour ago

                                      Correct, and you did ask specifically for OO things, but I thought I'd list namespaces too as far as “C++ things you might use when writing C-like C++ code”.

                                      Another big one that I always forget C still doesn't support is function overloading.

                              • Spivak 2 hours ago

                                I mean as long as your goal is specifically to do that I think it's fine. Using a C++ compiler to compile a C program isn't that rare.

                              • f1shy an hour ago

                                A couple of months ago, in the company I work, there was a talk from HR, where they explained how to make a good CV (the company is firing lots of people). She say: "if you have experience in programming C, you can writing just that, or, if you have lots of experience in C, is customary to write ``C++ Experience'' "

                                Sooo... yeah... I should definitely change company!

                                • kstrauser an hour ago

                                  That literally made me do a spit take, and it was fizzy water and it burned.

                                  My god. That's amazing.

                                • jpcfl 2 hours ago

                                  Bjarne should have called it ++C.

                                  • card_zero an hour ago

                                    Because people choose to use pre-increment by default instead of post-increment?

                                    Why is that?

                                    • int_19h an hour ago

                                      It should be ++C because with C++ the value you get from the expression is the old one.

                                      If you're asking why people use pre-increment by default instead of post-increment, it's mostly historical. The early C compilers on resource-constrained platforms such as early DOS were not good at optimization; on those, pre-increment would be reliably translated to a simple ADD or INC, whereas code for post-increment might generate an extra copy even if it wasn't actually used.

                                      For C++ this was even worse with iterators, because now it depended on the compiler's ability to inline its implementation of postfix ++, and then prove that all the copies produced by that implementation have no side effects to optimize it to the same degree as prefix ++ could. Depending on the type of the underlying value, this may not even be possible in general.

                                      The other reason is that all other unary operators in C are prefix rather than postfix, and mixing unary prefix with unary postfix in a single expression produces code that is easy to misunderstand. E.g. *p++ is *(p++), not (*p)++, even though the latter feels more natural, reading it left-to-right as usual. OTOH *++p vs ++*p is unambiguous.

                                      • card_zero 38 minutes ago

                                        K&R seems to use pre-increment early on, then post-increment consistently (or a lot, anyway, I haven't done a thorough check) after chapter 3, in situations where either would do. In fact, after introducing post-increment at 2.8.

                                      • tialaramex an hour ago

                                        Why use this operator? Like most C and C++ features the main reason tends to be showing off, you learned a thing (in this case that there are four extra operators here) and so you show off by using it even if it doesn't make the software easier to understand.

                                        This is not one of those beginner -> journeyman -> expert cycles where coincidentally the way you wrote it as a beginner is identical to how an expert writes it but for a very different reason. I'd expect experts are very comfortable writing either { x = k; k += 1; } or { k += 1; x = k; } depending on which they meant and don't feel an itch to re-write these as { x = k++; } and { x = ++k; } respectively.

                                        I'm slightly surprised none of the joke languages add equally frivolous operators. a%% to set a to the remainder after dividing a by 10, or b** to set b as two to the power b or some other silliness.

                                        • cozzyd 24 minutes ago

                                          It's more useful for pointers than for values, IMO

                                        • jejdjdbd an hour ago

                                          Why would you use post increment by default? The semantics are very particular.

                                          Only on very rare occasions I need post increment semantics.

                                          And in those cases I prefer to use a temporary to make the intent more clear

                                          • card_zero an hour ago

                                            People seem to mostly write a typical for loop ending with ; ++i){

                                            But I write ; i++){ and seeing it the other way round throws me off for a minute, because I think, as you put it, why would you use those very particular semantics?

                                            But I guess this is only a semantic argument.

                                            • johannes1234321 42 minutes ago

                                              > why would you use those very particular semantics?

                                              The difference is that i++ has to keep a copy to the original around as the return value is the pre-increment value, while with ++i that isn't needed as the resulting value is being returned.

                                              In the for loop that shouldn't matter as a) for an integer it is essentially for free (it is just reordering when the relevant register is set) and b) that value is hopefully optimized out anyways by the compiler, however as there are cases where it matters some people prefer the ++i style, some just think it looks better.

                                    • zkirill an hour ago

                                      I was going to ask if there is a good list of C books and then answered my own question. It categorizes _Modern C_ as Intermediate level.

                                      https://stackoverflow.com/questions/562303/the-definitive-c-...

                                      • auggierose 2 hours ago

                                        Table of contents in the sidebar doesn't work properly for me when I click on an entry (in macOS Preview).

                                        • f1shy an hour ago

                                          Doesn't work for me either... but I will not dismiss the book because of that.

                                          • bwidlar 2 hours ago

                                            I just test some links in the table of content, works fine for me. Using zathura pdf reader.

                                            • Jtsummers an hour ago

                                              Also works in Adobe and Firefox, but doesn't work in Chrome and Edge.

                                            • channel_t an hour ago

                                              Table of contents is definitely broken right now.

                                              • soegaard an hour ago

                                                Same here.

                                              • enriquto 2 hours ago

                                                So happy that we still get the dinosaur mascots! This is a good book.

                                                • bitbasher 2 hours ago

                                                  Really looking forward to #embed, once the compilers catch up. Until then, Golang.

                                                  • f1shy an hour ago
                                                    • enriquto 2 hours ago

                                                      This is not how C standards work. If it appears in the standard, it means that it is already implemented in some compilers (in that case, at least in gcc and clang).

                                                      • accelbred 28 minutes ago

                                                        I end up using a .S asm file with .incbin directives to embed files.

                                                        #embed would be much nicer

                                                        • jpcfl 2 hours ago

                                                          Or

                                                              xxd --include <file>
                                                          
                                                          :)
                                                          • rfl890 2 hours ago

                                                            Clang 19 has it.

                                                          • jumpman_miya an hour ago

                                                            in example 1.1 i read that as 'tits_square' until i saw the output

                                                            • glass-z13 an hour ago

                                                              that's by design

                                                            • ralphc an hour ago

                                                              How does "Modern" C compare safety-wise to Rust or Zig?

                                                              • WalterBright 4 minutes ago

                                                                Modern C still promptly decays an array to a pointer, so no array bounds checking is possible.

                                                                D does not decay arrays, so D has array bounds checking.

                                                                Note that array overflow bugs are consistently the #1 problem with shipped C code, by a wide margin.

                                                                • renox 12 minutes ago

                                                                  You'd be surprised: Zig has one UB (Undefined Behaviour) that C doesn't have!

                                                                  In release fast mode, unsigned overflow/underflow is undefined in Zig whereas in C it wraps.

                                                                  :-)

                                                                  Of course C has many UBs that Zig doesn't have, so C is far less safe than Zig, especially since you can use ReleaseSafe in Zig..

                                                                • zerr 38 minutes ago

                                                                  Do they still use 0-terminated strings/char* as the main string type?

                                                                  Is the usage of single linked lists still prevalent as the main container type?

                                                                  • racingmars 26 minutes ago

                                                                    > Do they still use 0-terminated strings/char* as the main string type?

                                                                    Of course, it's still C.

                                                                    > Is the usage of single linked lists still prevalent as the main container type?

                                                                    As far as I can remember, the C standard library has never had any functions that used linked lists. Nor are there any container types, linked lists or otherwise, provided by C. So I'd say this is a question about how people teach and use C, not related to the language -- or language spec version -- itself.