Live data from Hacker News

C constructs that still don't work in C++

lospino.so

101–110 of 182 posts

Re: C constructs that still don't work in C++

#101

I wrote this after repeatedly seeing experienced C programmers hit the same sharp edges while moving into modern C++ codebases. Many of these differences are intentional and defensible from the C++ side. But some are still surprising because they invalidate patterns that were historically common, performant, or idiomatic in C. The interesting part to me isn’t "C vs C++," but where the languages diverged philosophical…

> I wrote this after repeatedly seeing experienced C programmers hit the same sharp edges while moving into modern C++ codebases. ...I've seen this more often in the opposite direction. Since C++ is stuck with a ca 1995 non-standard subset of C, C++ coders usually have a very outdated view of C. > I’d also be curious which C constructs people still genuinely miss in modern C++. Not implementing the full C99 designate…

> It's especially tragic because Clang already had the full C99 designated init feature set in C++ mode implemented long before C++20 and it worked just fine.

How did Clang handle differences between member declaration order and the order in which initializers appeared?

Re: C constructs that still don't work in C++

#102

I wrote this after repeatedly seeing experienced C programmers hit the same sharp edges while moving into modern C++ codebases. Many of these differences are intentional and defensible from the C++ side. But some are still surprising because they invalidate patterns that were historically common, performant, or idiomatic in C. The interesting part to me isn’t "C vs C++," but where the languages diverged philosophical…

> I wrote this after repeatedly seeing experienced C programmers hit the same sharp edges while moving into modern C++ codebases. ...I've seen this more often in the opposite direction. Since C++ is stuck with a ca 1995 non-standard subset of C, C++ coders usually have a very outdated view of C. > I’d also be curious which C constructs people still genuinely miss in modern C++. Not implementing the full C99 designate…

> This was bad advice back then and is even worse advice today.

The languages have diverged a lot, it's true. Still, it is worth noting that all the code in TCPL 2nd Ed was compiled with Stroustrups C++ compiler, as there wasn't a C compiler available. Source: Preface/Acknowledgments.

Re: C constructs that still don't work in C++

#103
post #81

Earlier quoted context omitted.

About half of them read as "I tried to use C++ as a worse C" e.g. using struct initilisation instead of constructors, using malloc instead of new or new[]. My pet peeve with C++ is that the sequence point operator can be overloaded at which point it stops being a sequence point.

What's the "sequence point operator"?

,

Re: C constructs that still don't work in C++

#104
post #81

I wrote this after repeatedly seeing experienced C programmers hit the same sharp edges while moving into modern C++ codebases. Many of these differences are intentional and defensible from the C++ side. But some are still surprising because they invalidate patterns that were historically common, performant, or idiomatic in C. The interesting part to me isn’t "C vs C++," but where the languages diverged philosophical…

About half of them read as "I tried to use C++ as a worse C" e.g. using struct initilisation instead of constructors, using malloc instead of new or new[]. My pet peeve with C++ is that the sequence point operator can be overloaded at which point it stops being a sequence point.

As the title indicate, this article is comparing construct-to-construct, not idiomatic code to idiomatic code. You probably won't use struct initialization in C++, yet the feature still exist, so it may be useful to someone to compare it to the similar feature in C.

Re: C constructs that still don't work in C++

#105
post #80
post #27

Earlier quoted context omitted.

There is not much real evidence for "devs wrongly assume" and as someone writing numerical code (clusters, NUMA, SIMD, etc.) I think C is still the ideal tool for this.

Why should it be, the language doesn't expose any of it.

Assuming you mean the standard does not provide features for numa and simd? It doesn't necessarily have to. I think it is not surprising that you seem always bewildered that people still use C (as per your comments), as it seems you fundamentally do understand neither standardization nor systems programming.

Re: C constructs that still don't work in C++

#106

I find variable-length arrays (i.e. arrays whose length is defined at run-time and typically live on the stack) to be kind of dangerous, and try to avoid them, even in C.

A type of VLA I would like to see more of in C code however, is variable-length array parameters (void func(int n, int arr[n]);) and array pointers (int (*my_array)[n];).

Compilers can often do some static bounds-checking of such arrays. But because those features had been introduced together with variable-length array stack variables , people have lumped them all together and thus shunned these features that could otherwise have added safety.

BTW, one thing you should never do is use variable-length array declarations and alloca() in the same function. As VLA variables have scope life-time and allocas have function life-time they are not compatible — and allocations could overlap. Yet, not all compilers (/versions) that support both warn when they are used together.

Re: C constructs that still don't work in C++

#107
post #46
post #42

Earlier quoted context omitted.

Rust is also the systems programming language of the future. They're pretty much doing everything right.

What IMHO Rust does not get right and why I do not use it: long compilation times, high complexity, its syntax, polymorphism based on monomorphization, the requirement for many dependencies to get anything done, an ecosystem susceptible to supply-chain attacks, no ISO standard.

> its syntax

I haven’t used rust, but having gotten used to C and C++ at a time, I expect that would happen with rust, too, if I started using it. Because of that, I think this is just a matter of familiarity.

> polymorphism based on monomorphization

Implementation detail (yes, there is only one implementation at the moment, but this means it can be changed without changing the language)

> the requirement for many dependencies to get anything done

Fixable if a party is willing to write or package together a fairly large set of dependencies into a single package.

> an ecosystem susceptible to supply-chain attacks

Fixable if that party is trustworthy. Also, for which languages is this less of a problem? You either have third-party libraries and a potential security problem, or you don’t, and need to write more code.

Re: C constructs that still don't work in C++

#108
post #73
post #58

Earlier quoted context omitted.

Out of curiosity, what do you think is wrong with monomorphization-based polymorphism? The other alternatives I'm aware of are 1. type-erasure via v-table based dynamic dispatch (which Rust also has in the form of the `dyn` keyword), which has performance and memory-allocation overhead and 2. macros, which Rust also has and, if used for polymorphism, would essentially be like compile-time monomorphization, but clunki…

The correct choice IMHO is type-erasure. It does not necessarily have overhead, because optimizers can specialize or devirtualize. Of course, this my depend on how you implement your language, but in C this works nicely. The problem with monomorphization is that it leads to exponential expansion, which later passes of the compiler can not unify again (at least this is much harder than not expanding in the first place…

I don't think the numbers bear out that "this works nicely" in C, it seems like you have worse perf numbers for some common cases like sorting ?

Re: C constructs that still don't work in C++

#109
post #99

Earlier quoted context omitted.

and you CAN use static_cast to convert from void*; this silently keeps working if you refactor the void* into a matching-type pointer later, while raising a compilation error if you refactor to a different-type pointer.

Yes, a static_cast would be safe, but then most C++ seems to use a C-style cast because it is less clunky and then is less safe than the corresponding C code. The issue is not that the downcast is unsafe (it is, but once you have a void pointer you already accepted this), but that it becomes even less safe by adding a C-style cast. It is also not clear what is gained by forcing programmers to add a cast. Void pointer…

> but then most C++ seems to use a C-style cast

If C++ programmers do not use modern safety features, that's really their fault. C-style pointer casts should be flagged in code review.

> but that it becomes even less safe by adding a C-style cast.

At least in C++ there is a safer option. If you really want to be on the safe side, you can even to a dynamic_cast (assuming your code base allows RTTI).

> It is also not clear what is gained by forcing programmers to add a cast.

I think the point is to make it explicit and stand out.

Re: C constructs that still don't work in C++

#110

Earlier quoted context omitted.

> I wrote this after repeatedly seeing experienced C programmers hit the same sharp edges while moving into modern C++ codebases. ...I've seen this more often in the opposite direction. Since C++ is stuck with a ca 1995 non-standard subset of C, C++ coders usually have a very outdated view of C. > I’d also be curious which C constructs people still genuinely miss in modern C++. Not implementing the full C99 designate…

> It's especially tragic because Clang already had the full C99 designated init feature set in C++ mode implemented long before C++20 and it worked just fine. How did Clang handle differences between member declaration order and the order in which initializers appeared?

It simply reorders them, same behaviour as in C:

https://www.godbolt.org/z/ex138rh51

(the warnings in C++ mode had only been added after C++20)

Post reply on HN