Most people build C in g++ before gcc, as it tends to have a better chance of catching most oddities. Then run it past valgrind to double check if something looks suspect or is slowly leaking. =3

> Most people build C in g++ before gcc

That's not possible for 'standard C' though, only for the separate language that's called "the common subset of C and C++". E.g. it works more or less by accident for some specific C code that predates C99, but even that is built with C++ semantics (which has many subtle and some not-so-subtle differences to C semantics).

Instead of trying to build C in C++ mode, turn all the warnings to 11 (and also include warnings that aren't in -Wall -Wextra, like -Wsign-conversion).

Agreed, the point of divergence is already C89, not C99.

The C++ compatibility with C, is "As Close as Possible to C, but no Closer", meaning supporting C should not break the stronger type checking or the improved type system C++ has over C.

As such, besides C89 original differences, compatibility has only been added for C features that don't clash with C++ approach to the same problem, and while the C++ standard library keeps up with ISO C, it also does so taking into consideration C++ features for the implementation of said library functions.

"Sibling Rivalry: C vs C++"

https://www.stroustrup.com/sibling_rivalry.pdf

"C and C++: Siblings"

https://www.stroustrup.com/siblings_short.pdf

"C and C++, a case for compatibility"

https://www.stroustrup.com/compat_short.pdf

Two examples of the library updates,

"C++17 should refer to C11 instead of C99"

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p00...

"C++26 should refer to C23 not C17"

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p33...

The 'g++ -x c ...' will parse portable source just fine (compiles code as C, but links against libstdc++), and tends to identify poorly structured code with verbose checks. If people default to gcc file extension inference, than it is likely to remain silent when people do something silly.

Best of luck, =3

https://www.man7.org/linux/man-pages/man1/g++.1.html

Tbh I would be very surprised if `g++ -x c` and `gcc` use different language frontends.

One silly side effect of compiling C in C++ mode is that it forces you to cast from void pointers. E.g. the famous example of:

    bla_t* bla = (bla_t*)malloc(sizeof(bla_t));
That extra cast is just a silly and completely pointless C++-ism. It's only the tip of the iceberg though (another difference was zero-initialization with `{}` vs `{0}`, but that's harmonized now in C23 so that `{}` is also valid in C, but as soon as you want to use C99 designated init, the 'harmonization' ends).

One critical missing piece of C compilation mode was usually that the compiler didn't warn when using a wrong enum type, but that's also fixed by now (assuming `-Wall -Wextra`, but that should always be enabled anyway, otherwise you're just flying blind), e.g.:

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

Yes, g++ -xc will call the regular C FE.

So yes, do not try to compile C code using a C++ compiler.

That you somehow get superior type checking with C++ is not really true anymore, as essentially all important parts were integrated into the C standard and the remaining should all exist as optional warnings in gcc. If you feel something is missing, please file a bug.

The key logical jump here is "should", but in practice standards compliant C may still behave in unintuitive ways in edge-cases. It is not a compiler "bug" if functioning as defined, but rather a self-discipline issue to avoid shitty coding practices. =3

Just because a bit of C code compiles without diagnostics as C++ does not mean the code is safe. C++ does not have compound literals, but the syntax for a compound literal is accepted in several C++ compilers, including GCC and clang. However, in C compound literals have block-scoped lifetime, whereas C++ compilers give them expression-scoped lifetime. This means you can have silent use-after-free issues when using a C++ compiler. And, yes, I have encountered this (after diagnosing some read and write overflows in Valgrind and ASAN) and now try not to use compound literals in header files unless guarded to prevent accidental use with C++ compilers), though unfortunately this was a one of my later hard earned lessons.

Indeed, every C compiler including gcc is slightly different. Especially in the embedded space where pseudo-standards become a small subset of GNU compatible code very quickly. To be honest, gcc became the unofficial standard even with the GNU extensions.

Good C follows the 10 rules, uses old compatible macro language features, and is boring to trivially port. The "hold my beer" folks often go back to Python where the abstractions hide the foot-guns.

https://en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Dev...

What specific examples do you have in mind where you would get a useful warning with a C++ compiler that you can not also get for C with gcc?

It had to do with the lack of helpful warning/error messages while porting over a C project. Switching out for libstdc++ was helpful in narrowing the scope of where to look for the issue, and a better idea of the failure mode.

Given the Sealioning problem on YC, trying to remember an edge case issue from years ago would not go well. If your work habits aren't pushing into the compiler standards gray areas, than one probably won't ever encounter such issues. ymmv =3

https://www.youtube.com/watch?v=T4Upf_B9RLQ

Ray William Johnson…?