This feels like a straw man. I use C/C++ when I’m talking about properties common to both languages, most often about the abstract machine, for example:
Manual memory management via explicit allocation and deallocation.
Ownership via convention and helpers, not part of the type system.
Uncontrolled aliasing.
A specific memory model for atomics.
Direct access to all of the types and functions in the C standard library and declared in headers without any bridging.
An object model that has structures, arrays, pointers and a handful of primitives that map to machine types.
C++ has a lot of nice syntactic sugar over C but, with the exception of exceptions, you can write C code that compiles down to exactly that same machine code as C++. I vastly prefer writing the C++ because it is more concise and does a lot more checks at compile time, but both languages live in the C/C++ abstract machine.
Agreed. Even as someone with definite feelings about the difference between the two (and with the opposite preference to yours!), it seems pretty silly to pretend they don’t have plenty in common that their overlap is a meaningful, useful thing to talk about.
The second paragraph in particular struck me as pretty disingenuous, totally (willfully?) missing the point. C and C++ have enough in common that many programs are compilable (and semantically equivalent) in both languages. None of the other languages mentioned have that property; if you’re bringing FFIs into the mix you’re talking about something very different.
Honestly, I’m struggling to think of any other pair of languages that are more similar – all the other potential candidates I can come up with seem more like dialects than distinct languages (though that’s of course a pretty grey area).
Honestly, I’m struggling to think of any other pair of languages that are more similar
The obvious example would be C and Objective-C, since the latter is a superset of the former (every valid C program is the same valid program in Objective-C), but the fact that I often write [Objective-]C[++], just highlights the point. Perhaps equally importantly, they are typically compiled with the same compilers. For all four languages, clang uses the same parser with a few tweaks to determine which variant it’s using and builds a common AST that can express all four languages.
There are probably some managed languages that have a similar property. For example, I think F# and C# can be mechanically translated to the other (at least, in theory) and can use each other’s data types, but favour different idioms. The only reason that people don’t tend to write C#/F# is that ‘the CLR’ or ‘.NET languages’ typically captures what they mean a bit better.
True, I forgot about Objective-C – though while it does (unlike C++) have the strict-superset relation, IMO what it adds on top of C seems significantly more divergent from C’s basic principles than what C++ adds, so ultimately I guess I still feel like C++ is (handwave handwave) “more similar” as a language.
IMO what it adds on top of C seems significantly more divergent from C’s basic principles than what C++ adds
On the other hand, I feel like there should be some kind of variant of Greenspun’s tenth rule about major C and C++ projects eventually reimplementing a bunch of Objective-C features. (Reference counting, reflection systems, object serialisation, dynamic dispatch registration similar to passing selectors, etc.)
I have some biases here (I still maintain the GNUstep Objective-C runtime), but I think there’s a counter rule in here somewhat, which is that for any sufficiently flexible abstraction, users will try to build systems with a small subset of it. Objective-C’s dynamic dispatch comes with some overhead and, in particular, the reflection everywhere makes dead code elimination impossible and prohibits inlining (well, not quite. I did implement speculative inlining for Objective-C but I don’t think anyone ever enabled it in production). It’s great for things like KVC/KVO and for being able to connect things up for serialisation in Interface Builder, but I care about those things in less than 10% of the objects in a typical program, yet pay for the, everywhere.
This is part of the reason why I’m so interested in structural typing. If you never cast a concrete type to a structural type then you can do static dispatch for it at all call sites and dead-code eliminate a lot of unused bits. Reachability analysis gives you a fairly good overapproximation of the called methods on types that are cast to interface types and lets you do write code that is as flexible as Smalltalk where it needs to be but as efficient to compile as C++ everywhere else.
Oh, don’t get me wrong, I was by no means advocating for Objective-C. I was merely making the observation that Objective-C’s additions to C are not as esoteric and as much of a departure from de facto practical use of C as the GGP poster was suggesting.
I’ve had the misfortune of being tasked to improve perf on a throughput-critical Objective-C code base (client for a particular network protocol in an iOS & Mac app) and after a few easy low-level wins, method call and heap object lifetime management overhead rapidly started dominating profiles. (Unfortunately one of very few engagements that ended in bad blood, as the client wanted big improvements on a shoestring budget and without major architectural changes to the code base. For once, my mistake was not to push for a de-facto rewrite.)
I once came up with a harebrained monomorphising idea for Objective-C method dispatch: at monomorphic-suspected call sites, keep a cached isa/IMP pair of the most recent target; check the incoming object’s isa against the cache and call straight to the cached IMP on hit. No idea if this would make up for the inflated code size however. (You’d also need a nil check where nonnullness couldn’t be statically proven.) I certainly lack the general compiler hacking and specific clang experience to try it out as a casual project. (The other aspect to this is that I wonder if call sites would be better as a 2-stage IMP lookup and indirect call at each site rather than objc_msgSend(); but maybe modern branch predictors are smart enough to also look at the return pointer for predicting indirect [tail] calls, to take into account the actual call site rather than the unpredictable objc_msgSend.)
I once came up with a harebrained monomorphising idea for Objective-C method dispatch: at monomorphic-suspected call sites, keep a cached isa/IMP pair of the most recent target; check the incoming object’s isa against the cache and call straight to the cached IMP on hit.
The GNUstep runtime was designed to support this, with an approach that was simplified in the v2 ABI. There is a global 64-bit counter that is incremented every time a dispatch table is updated (this turns out to be quite rare - there was originally one per dispatch table). This means that you can cache a method as a triple of the class, this counter value and the IMP that was the result from the lookup.
A couple of things make it annoying to do a simple compare. The first is that nil can be an object, the second is that objects may not have an isa pointer, they may have the class encoded in the low 1-3 bits. This means that you need some masking and a branch to tell if this really is an pointer with an isa pointer. This starts to look almost as complex as the fast-path lookup. If you do this early though, you can also add a check that is ‘if the IMP is a pointer to the function I expect, call that’ and then you can inline that call. This lets you inline small methods in a bunch of places. The other place where it seemed to be a pretty big win was for superclass messages, where you know the target class rather than having to look it up, so you’re really just checking the counter and redoing the loopup if it changes (i.e. rarely).
I did write some LLVM transforms to do these optimisations. I hoped in the early days of LLVM that the API (and ABIs) needed for passes would become stable enough that libraries could ship passes that optimised for their specific idioms but this never happened (largely because Google doesn’t understand the concept of code that is not in their monorepo).
The GNUstep runtime was designed to support this, with an approach that was simplified in the v2 ABI. There is a global 64-bit counter that is incremented every time a dispatch table is updated (this turns out to be quite rare - there was originally one per dispatch table). This means that you can cache a method as a triple of the class, this counter value and the IMP that was the result from the lookup
Sounds similar to the approach used by sicl (§16.4), though missing one refinement: in sicl, not only do different versions of the same class have different counters, different classes have different counters too, so you can just dispatch on the counter.
If you do this early though, you can also add a check that is ‘if the IMP is a pointer to the function I expect, call that’ and then you can inline that call.
You can do it late, too, because of the dependency-cutting effect of branches.
The V1 ABI had a counter per slot (method), but in Objective-C method replacement is sufficiently rare that the overhead from checking and maintaining individual counters reduced the number of cache misses by almost nothing relative to a global counter and the global counter significantly simplified the logic.
Honestly, I’m struggling to think of any other pair of languages that are more similar – all the other potential candidates I can come up with seem more like dialects than distinct languages (though that’s of course a pretty grey area).
Kotlin and Java are kind of like C++ and C to my mind. Kotlin basically has the exact same semantics as Java, just as C++ has the same semantics as C. When I say “semantics”, I’m talking about things like whether function arguments are passed by reference or copy, runtime type information, polymorphism/inheritance resolution, etc.
But, at the same time, Kotlin and Java are definitely different languages in that idiomatic Kotlin reads pretty differently to idiomatic Java: Kotlin having expression-oriented syntax is a big part of that, while top-level functions and variables, and the cleaner syntax around higher-order functions and/or closures being another big part.
At the same time, I would say that Scala and Java are not quite as good an example, because it’s not always quite as obvious what the equivalent Java code would be for given Scala code, whereas I find that Kotlin-to-Java is much more obvious, like figuring out the equivalent C from C++ code.
Only if you’re using C together with C++ would it be acceptable to say C/C++.
I think this applies to… a surprising amount of code out there. This is obviously anecdotal but I’ve done C++ on and off for a long time (since the early ‘00s and my last C++ contract was about two years ago – I so hope it’s the last one…) and I think “pure” C++ work accounted for less than 10% of that. Even on Windows, where C++ is a very big thing, you routinely end up interfacing with C libraries and writing both C and C++ glue code.
IMHO C/C++ is actually the right label almost every time. Unless you’re a C++-only shop. where the only C code that gets written is C++ code that accidentally happens to be valid C, too, and C and C++ codebases never mix, C/C++ is very much the right description, independent of how well the use of two languages is steered at the codebase level.
The RTOS that we released earlier in the year does not link any C libraries, though it does provide a freestanding C environment (in addition to a C++ one) and so we can run pure-C compartments.
Nobody who says C/C++ thinks they’re the same language. They’re just talking about properties these both languages share, which the smart pointers and templates and RAII and exceptions and iterators and all these other features and modern patterns of the totally different language with different paradigms still haven’t managed to meaningfully change.
“/” is short for “yes I know you have vectors, but [] is still not bounds checked and .at() is only used for well-actually, and CMake is just as annoying for both languages”.
Nobody who says C/C++ thinks they’re the same language.
e.g. HR often use it as a just another keyword without knowing anything at all about it. Some contemporary managers or architects use it as a pejorative shortcut for something „obsolete“ and „legacy“ while they are reinventing the wheel, unix, rediscovering old patterns or models and repeating old errors.
At least in the job descriptions it would be useful to specify, whether they do a) just C, b) mostly C++, c) something like 50:50 mix of both or d) this is just another irrelevant technology mentioned in the job description.
No. There are a lot of things that are common to those two and only those two languages*. Sometimes I say C, sometimes I say C++, and sometimes I say C/C++. It depends.
…did anyone else notice that the two “solutions” to the leetcode problem do completely different things, and that only the C version actually solves the problem as described? The C++ version is doing something entirely different, so yeah, obviously the code is going to look different. It would look different if you wrote the same algorithm in C. 😅
The first C++ solution I clicked on actually looks like this:
int maximumCount(vector<int>& nums) {
int n=0,p=0;
for(int i=0;i<nums.size();i++){
if(nums[i]>0) p++;
if(nums[i]<0) n++;
}
return max(p,n);
}
…which you might notice is nearly identical to the C version in the blog post.
I mean, if you’re gonna use the standard library for this, std::accumulate is the tool here, not std::equal_range:
int f(std::span<const int> s) {
using Sum = std::pair<int,int>;
auto [n,p] = std::accumulate(s.begin(), s.end(), Sum(), [](Sum s, int e) {
auto [n,p] = s;
return Sum{ n - (e >> 31), p - ((~e&-e) >> 31) };
});
return std::max(n,p);
}
Although C++ was based off of C when it was first created, these two languages have slowly drifted apart over the years to the point where they share less and less in common.
They still have enough in common that I was able to write an entire cryptographic library in the intersection of the two… though OK, I do say it’s “written in C”.
WG21 and WG14 also collaborate. For example, when C back-ported the atomic types from C++, it introduced _Atomic(), which can now be a macro. It’s always been the goal that you can include a C header in C++. Personally, I’d really like this to go away with modules and instead have the ability to parse C header files in purely C mode and just expose the relevant AST nodes into the C++ compilation unit.
I agree that C and C++ are very different languages. However, C++ programmers regularly interface with C libraries when writing C++ code. Libraries like the C POSIX library, GObject, libnm, SDL2, SQLite, Cairo and many more come to mind. It’s almost impossible to write useful C++ software without interfacing with some C API. The code at this interface is necessarily a mix between the two languages. The C/C++ terminology is apt because it reflects this state of affairs.
I’d just like to interject for a moment. What you’re referring to as Linux, is in fact, GNU/Linux, or as I’ve recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system made useful by the GNU corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX.
Many computer users run a modified version of the GNU system every day, without realizing it. Through a peculiar turn of events, the version of GNU which is widely used today is often called “Linux”, and many of its users are not aware that it is basically the GNU system, developed by the GNU Project.
There really is a Linux, and these people are using it, but it is just a part of the system they use. Linux is the kernel: the program in the system that allocates the machine’s resources to the other programs that you run. The kernel is an essential part of an operating system, but useless by itself; it can only function in the context of a complete operating system. Linux is normally used in combination with the GNU operating system: the whole system is basically GNU with Linux added, or GNU/Linux. All the so-called “Linux” distributions are really distributions of GNU/Linux.
I agree that the term C/C++ is confusing and should not be used in most cases (probably except situations when you are talking about combination of C and C++ code).
But this article seems to be quite biased and written from the perspective of a C programmer-enthusiast. But from the C++ point of view, there are also good reasons to not use the common name „C/C++“. The C language has its own complexities and dark sides and C parts of a C/C++ codebase have their own issues and traps. The C language might be called simple, but C programs are not simple nor easy to write and maintain. Memory management, error handling, working with strings (or even non-ASCII) etc. in „pure“ C is not easy at all. Both these languages are „bad“ – but in their own different ways.
This feels like a straw man. I use C/C++ when I’m talking about properties common to both languages, most often about the abstract machine, for example:
C++ has a lot of nice syntactic sugar over C but, with the exception of exceptions, you can write C code that compiles down to exactly that same machine code as C++. I vastly prefer writing the C++ because it is more concise and does a lot more checks at compile time, but both languages live in the C/C++ abstract machine.
Agreed. Even as someone with definite feelings about the difference between the two (and with the opposite preference to yours!), it seems pretty silly to pretend they don’t have plenty in common that their overlap is a meaningful, useful thing to talk about.
The second paragraph in particular struck me as pretty disingenuous, totally (willfully?) missing the point. C and C++ have enough in common that many programs are compilable (and semantically equivalent) in both languages. None of the other languages mentioned have that property; if you’re bringing FFIs into the mix you’re talking about something very different.
Honestly, I’m struggling to think of any other pair of languages that are more similar – all the other potential candidates I can come up with seem more like dialects than distinct languages (though that’s of course a pretty grey area).
The obvious example would be C and Objective-C, since the latter is a superset of the former (every valid C program is the same valid program in Objective-C), but the fact that I often write [Objective-]C[++], just highlights the point. Perhaps equally importantly, they are typically compiled with the same compilers. For all four languages, clang uses the same parser with a few tweaks to determine which variant it’s using and builds a common AST that can express all four languages.
There are probably some managed languages that have a similar property. For example, I think F# and C# can be mechanically translated to the other (at least, in theory) and can use each other’s data types, but favour different idioms. The only reason that people don’t tend to write C#/F# is that ‘the CLR’ or ‘.NET languages’ typically captures what they mean a bit better.
True, I forgot about Objective-C – though while it does (unlike C++) have the strict-superset relation, IMO what it adds on top of C seems significantly more divergent from C’s basic principles than what C++ adds, so ultimately I guess I still feel like C++ is (handwave handwave) “more similar” as a language.
On the other hand, I feel like there should be some kind of variant of Greenspun’s tenth rule about major C and C++ projects eventually reimplementing a bunch of Objective-C features. (Reference counting, reflection systems, object serialisation, dynamic dispatch registration similar to passing selectors, etc.)
I have some biases here (I still maintain the GNUstep Objective-C runtime), but I think there’s a counter rule in here somewhat, which is that for any sufficiently flexible abstraction, users will try to build systems with a small subset of it. Objective-C’s dynamic dispatch comes with some overhead and, in particular, the reflection everywhere makes dead code elimination impossible and prohibits inlining (well, not quite. I did implement speculative inlining for Objective-C but I don’t think anyone ever enabled it in production). It’s great for things like KVC/KVO and for being able to connect things up for serialisation in Interface Builder, but I care about those things in less than 10% of the objects in a typical program, yet pay for the, everywhere.
This is part of the reason why I’m so interested in structural typing. If you never cast a concrete type to a structural type then you can do static dispatch for it at all call sites and dead-code eliminate a lot of unused bits. Reachability analysis gives you a fairly good overapproximation of the called methods on types that are cast to interface types and lets you do write code that is as flexible as Smalltalk where it needs to be but as efficient to compile as C++ everywhere else.
Oh, don’t get me wrong, I was by no means advocating for Objective-C. I was merely making the observation that Objective-C’s additions to C are not as esoteric and as much of a departure from de facto practical use of C as the GGP poster was suggesting.
I’ve had the misfortune of being tasked to improve perf on a throughput-critical Objective-C code base (client for a particular network protocol in an iOS & Mac app) and after a few easy low-level wins, method call and heap object lifetime management overhead rapidly started dominating profiles. (Unfortunately one of very few engagements that ended in bad blood, as the client wanted big improvements on a shoestring budget and without major architectural changes to the code base. For once, my mistake was not to push for a de-facto rewrite.)
I once came up with a harebrained monomorphising idea for Objective-C method dispatch: at monomorphic-suspected call sites, keep a cached isa/
IMP
pair of the most recent target; check the incoming object’s isa against the cache and call straight to the cached IMP on hit. No idea if this would make up for the inflated code size however. (You’d also need a nil check where nonnullness couldn’t be statically proven.) I certainly lack the general compiler hacking and specific clang experience to try it out as a casual project. (The other aspect to this is that I wonder if call sites would be better as a 2-stage IMP lookup and indirect call at each site rather thanobjc_msgSend()
; but maybe modern branch predictors are smart enough to also look at the return pointer for predicting indirect [tail] calls, to take into account the actual call site rather than the unpredictableobjc_msgSend
.)The GNUstep runtime was designed to support this, with an approach that was simplified in the v2 ABI. There is a global 64-bit counter that is incremented every time a dispatch table is updated (this turns out to be quite rare - there was originally one per dispatch table). This means that you can cache a method as a triple of the class, this counter value and the IMP that was the result from the lookup.
A couple of things make it annoying to do a simple compare. The first is that nil can be an object, the second is that objects may not have an isa pointer, they may have the class encoded in the low 1-3 bits. This means that you need some masking and a branch to tell if this really is an pointer with an isa pointer. This starts to look almost as complex as the fast-path lookup. If you do this early though, you can also add a check that is ‘if the IMP is a pointer to the function I expect, call that’ and then you can inline that call. This lets you inline small methods in a bunch of places. The other place where it seemed to be a pretty big win was for superclass messages, where you know the target class rather than having to look it up, so you’re really just checking the counter and redoing the loopup if it changes (i.e. rarely).
I did write some LLVM transforms to do these optimisations. I hoped in the early days of LLVM that the API (and ABIs) needed for passes would become stable enough that libraries could ship passes that optimised for their specific idioms but this never happened (largely because Google doesn’t understand the concept of code that is not in their monorepo).
Sounds similar to the approach used by sicl (§16.4), though missing one refinement: in sicl, not only do different versions of the same class have different counters, different classes have different counters too, so you can just dispatch on the counter.
You can do it late, too, because of the dependency-cutting effect of branches.
The V1 ABI had a counter per slot (method), but in Objective-C method replacement is sufficiently rare that the overhead from checking and maintaining individual counters reduced the number of cache misses by almost nothing relative to a global counter and the global counter significantly simplified the logic.
I always loved writing Objective-C. I found it an extremely elegant tool.
A language is a dialect with an army and a navy.
Kotlin and Java are kind of like C++ and C to my mind. Kotlin basically has the exact same semantics as Java, just as C++ has the same semantics as C. When I say “semantics”, I’m talking about things like whether function arguments are passed by reference or copy, runtime type information, polymorphism/inheritance resolution, etc.
But, at the same time, Kotlin and Java are definitely different languages in that idiomatic Kotlin reads pretty differently to idiomatic Java: Kotlin having expression-oriented syntax is a big part of that, while top-level functions and variables, and the cleaner syntax around higher-order functions and/or closures being another big part.
At the same time, I would say that Scala and Java are not quite as good an example, because it’s not always quite as obvious what the equivalent Java code would be for given Scala code, whereas I find that Kotlin-to-Java is much more obvious, like figuring out the equivalent C from C++ code.
I’m sure you use C/C++ only to refer to both or common features, but for a lot of people, C/C++ usually just means C++.
I think this applies to… a surprising amount of code out there. This is obviously anecdotal but I’ve done C++ on and off for a long time (since the early ‘00s and my last C++ contract was about two years ago – I so hope it’s the last one…) and I think “pure” C++ work accounted for less than 10% of that. Even on Windows, where C++ is a very big thing, you routinely end up interfacing with C libraries and writing both C and C++ glue code.
IMHO C/C++ is actually the right label almost every time. Unless you’re a C++-only shop. where the only C code that gets written is C++ code that accidentally happens to be valid C, too, and C and C++ codebases never mix, C/C++ is very much the right description, independent of how well the use of two languages is steered at the codebase level.
Exactly, I mean what C++ program doesn’t link a pure C library?
Certainly say Chrome and Firefox are all in that category, and most C++ programs on Linux and Windows
I think LLVM/Clang are almost all C++ they wrote themselves, but I wouldn’t be surprised if they have some C too
The RTOS that we released earlier in the year does not link any C libraries, though it does provide a freestanding C environment (in addition to a C++ one) and so we can run pure-C compartments.
Nobody who says C/C++ thinks they’re the same language. They’re just talking about properties these both languages share, which the smart pointers and templates and RAII and exceptions and iterators and all these other features and modern patterns of the totally different language with different paradigms still haven’t managed to meaningfully change.
“/” is short for “yes I know you have vectors, but
[]
is still not bounds checked and.at()
is only used for well-actually, and CMake is just as annoying for both languages”.e.g. HR often use it as a just another keyword without knowing anything at all about it. Some contemporary managers or architects use it as a pejorative shortcut for something „obsolete“ and „legacy“ while they are reinventing the wheel, unix, rediscovering old patterns or models and repeating old errors.
At least in the job descriptions it would be useful to specify, whether they do a) just C, b) mostly C++, c) something like 50:50 mix of both or d) this is just another irrelevant technology mentioned in the job description.
Yeah. Given that recruiters still can’t tell Java from JS I didn’t even think to count them.
I assume TFA meant contexts like articles and comments from programmers.
As an engineer that works on clang I agree with the title at least.
The correct term is [Obj-]C/C++
:D
No. There are a lot of things that are common to those two and only those two languages*. Sometimes I say C, sometimes I say C++, and sometimes I say C/C++. It depends.
A bunch of years ago, a pal came up with a fun game: name two languages together that share a similar surface syntax, where being slash-tied to the other language offends users of either language.
My favorite remains Python/Makefile.
…wait, just due to having significant whitespace? Aside from that one detail I’d say those two have pretty wildly different syntaxes.
See, it works!
…did anyone else notice that the two “solutions” to the leetcode problem do completely different things, and that only the C version actually solves the problem as described? The C++ version is doing something entirely different, so yeah, obviously the code is going to look different. It would look different if you wrote the same algorithm in C. 😅
The first C++ solution I clicked on actually looks like this:
…which you might notice is nearly identical to the C version in the blog post.
I mean, if you’re gonna use the standard library for this, std::accumulate is the tool here, not
std::equal_range
:They still have enough in common that I was able to write an entire cryptographic library in the intersection of the two… though OK, I do say it’s “written in C”.
WG21 and WG14 also collaborate. For example, when C back-ported the atomic types from C++, it introduced _Atomic(), which can now be a macro. It’s always been the goal that you can include a C header in C++. Personally, I’d really like this to go away with modules and instead have the ability to parse C header files in purely C mode and just expose the relevant AST nodes into the C++ compilation unit.
C/C++
I agree that C and C++ are very different languages. However, C++ programmers regularly interface with C libraries when writing C++ code. Libraries like the C POSIX library, GObject, libnm, SDL2, SQLite, Cairo and many more come to mind. It’s almost impossible to write useful C++ software without interfacing with some C API. The code at this interface is necessarily a mix between the two languages. The C/C++ terminology is apt because it reflects this state of affairs.
I guess an argument could be made that C code is never interfaced with C++ (unless it has C interface).
I’d just like to interject for a moment. What you’re referring to as Linux, is in fact, GNU/Linux, or as I’ve recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system made useful by the GNU corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX.
Many computer users run a modified version of the GNU system every day, without realizing it. Through a peculiar turn of events, the version of GNU which is widely used today is often called “Linux”, and many of its users are not aware that it is basically the GNU system, developed by the GNU Project.
There really is a Linux, and these people are using it, but it is just a part of the system they use. Linux is the kernel: the program in the system that allocates the machine’s resources to the other programs that you run. The kernel is an essential part of an operating system, but useless by itself; it can only function in the context of a complete operating system. Linux is normally used in combination with the GNU operating system: the whole system is basically GNU with Linux added, or GNU/Linux. All the so-called “Linux” distributions are really distributions of GNU/Linux.
If I may interject for a moment, RMS would like you to stop spreading incorrect copypasta. Please give Torvalds some credit.
lol thanks I’ve not seen this; it makes the copypasta funnier somehow
This person is definitely occupying themselves with the real problems out there.
That was mean! I feel his point on hiring is spot on though. It is counterproductive to advertise for C/C++ while actually looking for C programmers.
I agree that the term C/C++ is confusing and should not be used in most cases (probably except situations when you are talking about combination of C and C++ code).
But this article seems to be quite biased and written from the perspective of a C programmer-enthusiast. But from the C++ point of view, there are also good reasons to not use the common name „C/C++“. The C language has its own complexities and dark sides and C parts of a C/C++ codebase have their own issues and traps. The C language might be called simple, but C programs are not simple nor easy to write and maintain. Memory management, error handling, working with strings (or even non-ASCII) etc. in „pure“ C is not easy at all. Both these languages are „bad“ – but in their own different ways.