Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

No, C is not a simple language

198 views
Skip to first unread message

Juha Nieminen

unread,
Apr 17, 2021, 1:57:04 AM4/17/21
to
I know that this is probably going to piss off avid C programmers,
but I don't really care all that much.

Many C fans keep insisting how C is so much better than C++ because
C++ is so utterly complicated, with a standard that reads like a
phonebook and a standard library so vast that nobody in their sane
mind could ever even hope to remember all of it, and how C++ is
becoming more and more complicated with every standard, and how
C is such a simple, straightforward and beautiful language, so
immensely better than C++.

I myself happen to know both languages quite well, and in fact I
program in both languages as my profession, and I would say that
I am very knowledgeable and proficient in both languages and have
no trouble in developing in either one. I am of the strong opinion
that no, C is not a "simple" language, and that C++ makes so many
things so much simpler, easier and safer.

I was reminded of this in a quite concrete manner recently when I was
trying to help a beginner programmer who had decided to try his hands
on C, and wanted to create a simple text editor, which would read a
text file, allow the user to edit the text in several ways, and to
save the file.

It quite quickly turned very frustrating for *both* of us that dynamic
string manipulation in C is so damn complicated, especially for a
complete beginner who has never programmed in C, and has only very
little experience even with other programming languages (he had some
very small experience with Python.)

I tried approaching the problem by explaining that for a project of
this nature and size, it would be much more better to create a separate
(and reusable) "string" module, ie. a struct that represents a string
(which has a char* and a length member variable), and a bunch of functions
that operate on objects of that struct type, clearly and logically
named. (In other words, I was trying to make him essentially replicate
a subset of std::string in C.) This would make it much easier to do
things like appending strings to other strings, inserting characters
and strings in the middle of other strings (having them automatically
grow dynamically), and so on.

Even then, it was just frustration after frustration, trying to explain
and make him understand why in C you need to always explicitly call an
initializer function (ie. "constructor") for every single new string
object (and any struct that may have such a string object as a member
variable, and any struct that may have those types of structs as
members, all the way down), and especially how you have to make sure
to call the destruction function for every such object, or else there
would be a leak.

It's surprisingly complicated and frustrating to try to explain to a
complete beginner how and why he should follow very strict coding
practices when it comes to initializing and destructing every object
and, especially, why he should be very careful about assigning string
objects to each other directly. In the middle of this mountain of new
complicated information, try to explain to a complete beginner the
subtleties of doing this:

String str1 = String_with_cstr("hello");
String str2 = str1;

While not wrong per se, and it actually does have its uses, it's very
prone to errors because now str1 and str2 are pointing to the same
string data, so only one of them must be destroyed and the other must
not be used after that (unless it's initialized again).

Also, trying to inculcate how wrong this is, and how important it is
to avoid it:

String str1 = String_with_cstr("hello");
String str2 = String_with_cstr("there");
str1 = str2; // No!

He also asked why he couldn't do something like this:

String str = "hello";

Now try to explain why that doesn't directly work (obviously causes
a compiler error), and try to think whether you should explain that
he *can* assign the string literal to the member char* of the struct
(remember to also update the length parameter) but once again how fraught
with peril that is, because now he will have to remember to *not* destruct
*this* particular object, or else bad things will happen.

Then try to explain the concept of string capacity vs its length,
which is useful in this kind of module because of efficiency reasons
(and also because the string may become shorter, while retaining its
capacity).

The worst thing, however, was trying to inculcate the importance of
always properly initializing and destructing the objects at the proper
places, and to avoid the pitfalls and mistakes that are so easy to make
when handling such objects.

And those are just a couple of examples from many. I couldn't help but
to constantly comment how much easier all this would be in C++, using
std::string, where you don't have to worry about any of that. The
project he was trying to make was almost *trivial* to do in C++, because
of the readymade tools available in the standard library, and the
ease and safety mechanisms provided by the language. Instead of writing
thousands of lines of code to create his own string class, and then
having to follow strict coding practices to avoid mistakes when creating
dynamic arrays of such string objects, in C++ he could just create a
std::vector<std::string> and be done with it. All the tools he needed
for that project available easily and safely.

Christian Gollwitzer

unread,
Apr 17, 2021, 2:43:15 AM4/17/21
to
Am 17.04.21 um 07:56 schrieb Juha Nieminen:
> I know that this is probably going to piss off avid C programmers,
> but I don't really care all that much.
>
> Many C fans keep insisting how C is so much better than C++ because
> C++ is so utterly complicated, with a standard that reads like a
> phonebook and a standard library so vast that nobody in their sane
> mind could ever even hope to remember all of it, and how C++ is
> becoming more and more complicated with every standard, and how
> C is such a simple, straightforward and beautiful language

I fully agree and I think there is a confusion about the word "simple".

C is definitively a simple language in the sense that the definition of
it is small, therefore the code maps very directly to the underlying
assembly and it is easy to write a compiler for.

That, however, doesn't make it simple to *use*, rather the opposite -
otherwise we would be coding in Brainfuck or lambda calculus, these are
inherently simple languages.

C++'s quirks actually come from the forced compatibility with C, for
example why is this "abc" not a string, but a pointer? Why are unsigned
integers used not only for bit-twiddling?

std::string test = "abc" + "def"; // Very strange error
for (size_t c=5; c>=0; c--); // endless loop


For a language to be simple to use, it needs a way to express the intent
of the programmer in the language he thinks in. This varies for
different domains of computing:

Numerical algorithms -> infix math, linear algebra
Data structures -> List comprehensions, functional programming
Controlling hardware, IO -> Serial/Iterative programming
GUIs -> Classes and Inheritance

Otherwise, the programmer is forced to shoehorn the problem into the
language. This is easily shown by the abominations of Java's forced-OO
APIs and "Design patterns" or when you try to do numerical math in Lisp.

To be simple to *use*, a language must be complex - because then you can
choose the right paradigm for your work. Another example: A pocket
calculator is so much simpler and more beautiful than a current
computer! But we wouldn't use it to calculate the stability of a bicycle
frame using it.



Christian

wij

unread,
Apr 17, 2021, 2:49:46 AM4/17/21
to
One reason C programmer do not like C++ is C++ does things in the background
Good or bad? not easy to say shortly.
But something is sure, pretty much in all cases, programmers sooner or latter will
need to know those underlying things, C or better, Assembly. C++ is no exception.

MrSpo...@g9b2a_ex9aicgvs04.net

unread,
Apr 17, 2021, 6:27:50 AM4/17/21
to
On Sat, 17 Apr 2021 05:56:42 +0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
>It quite quickly turned very frustrating for *both* of us that dynamic
>string manipulation in C is so damn complicated, especially for a
>complete beginner who has never programmed in C, and has only very
>little experience even with other programming languages (he had some
>very small experience with Python.)

Umm, asprintf()


>Now try to explain why that doesn't directly work (obviously causes
>a compiler error), and try to think whether you should explain that
>he *can* assign the string literal to the member char* of the struct
>(remember to also update the length parameter) but once again how fraught
>with peril that is, because now he will have to remember to *not* destruct
>*this* particular object, or else bad things will happen.
>
>Then try to explain the concept of string capacity vs its length,
>which is useful in this kind of module because of efficiency reasons
>(and also because the string may become shorter, while retaining its
>capacity).

Any powerful language is hard to learn at the start. Try telling a beginner
about C++ virtual function overloading or templates and watch the blank
expression appear. However once someone DOES know C or C++ it all becomes
2nd nature.

jacobnavia

unread,
Apr 17, 2021, 11:43:33 AM4/17/21
to
Le 17/04/2021 à 07:56, Juha Nieminen a écrit :
> I know that this is probably going to piss off avid C programmers,
> but I don't really care all that much.
>

It is funny how comic you look trying to convince people that C is
complicated, even more complicated than c++, imagine that. Obviously I
am one of those "avid" C programmers that never quite got into the c++
bandwagon.

> Many C fans keep insisting how C is so much better than C++ because
> C++ is so utterly complicated, with a standard that reads like a
> phonebook and a standard library so vast that nobody in their sane
> mind could ever even hope to remember all of it, and how C++ is
> becoming more and more complicated with every standard, and how
> C is such a simple, straightforward and beautiful language, so
> immensely better than C++.
>

The whole C language fits in your brain without overflowing it with
computer trivia. Try that with c++.
>

[snip]

> Also, trying to inculcate how wrong this is, and how important it is
> to avoid it:
>
> String str1 = String_with_cstr("hello");
> String str2 = String_with_cstr("there");
> str1 = str2; // No!
>

Did you try to explain him about why c++ has similar problems?

For instance:
#include <iostream>
#include <string>
#include <string_view>

int main() {
std::string s = "Hellooooooooooooooo ";
std::string_view sv = s + "World\n";
std::cout << sv;
}

Here, the expression s + "World" yields a std::string that is converted
to a string view and immediately freed. Each time you use the string
view you risk a segmentation fault.

Now, try to explain that to a beginner!


And of course you did NOT tell that beginner that he could avoid all
accounting problems with strings if ne NEVER frees any string and just
uses Boehm's GC that is available for C since more than a decade.


You are ignoring how to use C efficiently and using the right tools.

> He also asked why he couldn't do something like this:
>
> String str = "hello";
>

He could do:
const String str = { 5, "hello"};

But that is beyond the poor beginner's brain capacity or what?

Obviously assuming that writing a text editor for a guy that doesn't
know much about programming is an "easy" task is not an error from YOUR
side!

Nonsense really

Manfred

unread,
Apr 17, 2021, 1:12:56 PM4/17/21
to
(cross-posting to comp.lang.c to let the heat fire up)

On 4/17/2021 7:56 AM, Juha Nieminen wrote:
> I know that this is probably going to piss off avid C programmers,
> but I don't really care all that much.

Excellent start

[...]
>
> I myself happen to know both languages quite well, and in fact I
> program in both languages as my profession, and I would say that
> I am very knowledgeable and proficient in both languages and have
> no trouble in developing in either one. I am of the strong opinion
> that no, C is not a "simple" language, and that C++ makes so many
> things so much simpler, easier and safer.
>
> I was reminded of this in a quite concrete manner recently when I was
> trying to help a beginner programmer who had decided to try his hands
> on C, and wanted to create a simple text editor, which would read a
> text file, allow the user to edit the text in several ways, and to
> save the file.
>
> It quite quickly turned very frustrating for *both* of us ...

The first comment that comes to mind is that probably part of the
frustration stems from your approach (no offense) to try and use in C a
design that would be suitable for C++ instead. Despite their name, the
two are quite different languages. The similarities are about their
runtime footprint, not about how they are used.

For example, at a first glance the design of string object is not that
great for C.
A common pattern that pops to the mind is to use opaque structs (see
e.g. FILE*), and have something like:

typedef struct string_t STRING;

STRING* alloc_string(); // creates the empty string
STRING* set_string(STRING* s, const char* value);
void free_string(STRING* s);
STRING* concat_string(STRING* s1, STRING* s2);
...

This way there would be no ambiguity about how the STRING object has to
be used.
And yes, in C you have to do all yourself - C is a low level language,
and it is meant for low level stuff. It is hardly the right tool for
anything meant to interface with a human user - it is (still) great for
system programming and back-end processing, IMO.

As second, I agree with Jacob that a text editor is a simple tool, but
it is not easy to make expecially for a beginner.


[snip]

Bonita Montero

unread,
Apr 17, 2021, 3:36:44 PM4/17/21
to
> I am of the strong opinion that no, C is not a "simple" language,
> and that C++ makes so many things so much simpler, easier and safer.

Of course C is a very simple language, i.e. the language itself is very
easy to understand. But it hard to develop in C because C lacks almost
every modern language facility. C++ as the language itself is hard to
understand, but if you've managed to understand it, it is by magnitudes
easier to develop with C++.

Paavo Helde

unread,
Apr 17, 2021, 5:48:15 PM4/17/21
to
17.04.2021 08:56 Juha Nieminen kirjutas:
> Many C fans keep insisting how C is so much better than C++ because
> C is such a simple, straightforward and beautiful language, so

This claim might be true, but this has no relevance to whether C should
be used for a given task. For any given task one should choose the best
fitting tool, not the simplest one.

For example, the simplest reliable tool for ensuring a horizontal level
is a water-filled hose. OTOH, the easiest one to use is generally a
cross line laser, built on technologies whose very existence is still
not believed by some people. Nothing simple there.

However, in some circumstances, like with limited access and no clear
line of sight, a water-filled hose might still yield a better result
than any high-tech alternative (e.g. GPS).

So, for each usage there is a best tool. Sometimes the tool is itself
simple, sometimes it's not. Sometimes there is no good tool and one
needs to invent a new one (inventing TeX for typesetting comes to mind).

Juha Nieminen

unread,
Apr 18, 2021, 12:26:07 PM4/18/21
to
wij <wyn...@gmail.com> wrote:
> One reason C programmer do not like C++ is C++ does things in the background
> Good or bad? not easy to say shortly.

I can't think of many things that C++ "does in the background". Perhaps the
most prominent (and perhaps the most controversial) thing is exceptions.
However, even then, originally exceptions were accepted into the first C++
standard only if it could be proven that they could be implemented "for
free" (ie. exception support would not slow down the program in any way
if exceptions are not thrown). It's my understanding that the standardization
committee was satisfied enough with the techniques that were possible and
accepted them.

Of course one could also argue that RAII and compiler-generated constructors
and assignment operators are things that the compiler does "in the
background", but I would argue those are only beneficial, not detrimental.
And most importantly, they rarely come as a surprise to the programmer.
RAII certainly makes many things simpler (like in this example.)

(Rather obviously the standard library doesn't really count as "C++ doing
things in the background" because else you could make the same argument
from the C standard library.)

Juha Nieminen

unread,
Apr 18, 2021, 12:30:29 PM4/18/21
to
MrSpook_wb@g9b2a_ex9aicgvs04.net wrote:
> On Sat, 17 Apr 2021 05:56:42 +0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:
>>It quite quickly turned very frustrating for *both* of us that dynamic
>>string manipulation in C is so damn complicated, especially for a
>>complete beginner who has never programmed in C, and has only very
>>little experience even with other programming languages (he had some
>>very small experience with Python.)
>
> Umm, asprintf()

Use a non-standard-C non-posix compiler extension for... what, exactly?
Doesn't help one bit with allocation and deallocation of string
objects.

If you are going to suggest functions that are not part of the
standard language, you could just as well recommend using Python
or something.

> Any powerful language is hard to learn at the start. Try telling a beginner
> about C++ virtual function overloading or templates and watch the blank
> expression appear.

Why? He wanted to make a simple text editor, which manipulates dynamically
allocated strings. What do virtual functions or templates have anything
to do with this?

Juha Nieminen

unread,
Apr 18, 2021, 12:39:34 PM4/18/21
to
jacobnavia <ja...@jacob.remcomp.fr> wrote:
>> Also, trying to inculcate how wrong this is, and how important it is
>> to avoid it:
>>
>> String str1 = String_with_cstr("hello");
>> String str2 = String_with_cstr("there");
>> str1 = str2; // No!
>>
>
> Did you try to explain him about why c++ has similar problems?

I always love it when C programmers try to come up with the most
contrived ways to defend their beloved language.

You didn't actually give an argument of why C would be better for the
beginner in question than C++, who only wanted to create a simple text
editor that manipulates dynamically allocated strings. Instead, you
deliberately came up with a contrived example that has nothing to do
with it.

> And of course you did NOT tell that beginner that he could avoid all
> accounting problems with strings if ne NEVER frees any string and just
> uses Boehm's GC that is available for C since more than a decade.

Why not just recommend him to use Python, while we are at it? All the
problems solved.

The funny thing is that you seem to be completely oblivious to the fact
that you are trying to recommend a fix to a flaw in the language, while
still defending the language.

>> He also asked why he couldn't do something like this:
>>
>> String str = "hello";
>>
>
> He could do:
> const String str = { 5, "hello"};
>
> But that is beyond the poor beginner's brain capacity or what?

I already explained why that's such a horrible idea in C, when the
'String' struct is supposed to hold a dynamically allocated string
that you are supposed to destroy before it goes out of scope.

You are writing that as if I didn't know that.

Juha Nieminen

unread,
Apr 18, 2021, 12:47:12 PM4/18/21
to
In comp.lang.c++ Manfred <non...@add.invalid> wrote:
> For example, at a first glance the design of string object is not that
> great for C.
> A common pattern that pops to the mind is to use opaque structs (see
> e.g. FILE*), and have something like:
>
> typedef struct string_t STRING;
>
> STRING* alloc_string(); // creates the empty string
> STRING* set_string(STRING* s, const char* value);
> void free_string(STRING* s);
> STRING* concat_string(STRING* s1, STRING* s2);
> ...
>
> This way there would be no ambiguity about how the STRING object has to
> be used.

I see no practical difference between that and a String struct. The usage is
pretty much the same, and all the same problems appear (such as assigning
one string object/pointer to another requiring extra care to avoid destroying
the string twice or accessing a destroyed string).

Juha Nieminen

unread,
Apr 18, 2021, 12:49:28 PM4/18/21
to
Bonita Montero <Bonita....@gmail.com> wrote:
> Of course C is a very simple language, i.e. the language itself is very
> easy to understand.

Where does that misconception come from?

Even many experienced C programmers will have difficulty in understanding eg.
the most complex function and array pointers, or even remember their syntax
(there's a reason why sites like cdecl.org exist.)

Manfred

unread,
Apr 18, 2021, 2:31:07 PM4/18/21
to
If the struct is opaque, the compiler won't allow you to assign a STRING
object to another, as a start. In fact it won't allow to perform /any/
operation on the object, except through the API that you define.

You can still mess up with pointers, but if you want to use C, then you
have to know better.

This is nothing new, as I wrote the entire FILE* infrastructure works
this way.

jacobnavia

unread,
Apr 18, 2021, 2:48:17 PM4/18/21
to
Le 18/04/2021 à 18:39, Juha Nieminen a écrit :
> The funny thing is that you seem to be completely oblivious to the fact
> that you are trying to recommend a fix to a flaw in the language, while
> still defending the language.

Obviously C strings are a flaw in the language. C is not the perfect
language. C++ isn't flawless either. Python has the excellent idea that
white space (tabulations) have a semantic meaning, imagine that...

Rust has its "unsafe" keyword that voids any advantages the language may
have, lisp has too much parenthesis for anybody's taste.

Should I go on?

Rants like this are completely sterile

Keith Thompson

unread,
Apr 18, 2021, 3:46:24 PM4/18/21
to
Except that you *can* assign objects of type FILE (if you don't mind
undefined behavior). The FILE type is opaque in the sense that the
standard doesn't say what it looks like, but it has to be an object
type.

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

Manfred

unread,
Apr 18, 2021, 4:53:52 PM4/18/21
to
The relevant part was:

> typedef struct string_t STRING;

I am talking about opaque types, which are incomplete and as such you
can't use objects of their type.

As far as the standard is concerned FILE is an opaque type whose
definition might not be seen (and in fact is _not_ intended to be seen,
let alone used) by user code.
I think it is clear that the fact that in some implementations the
definition of FILE might percolate into user TUs is orthogonal to this
discussion.

$ cat opaque.c
typedef struct string_t STRING;

STRING* string_concat(STRING* s1, STRING* s2);
void string_free(STRING* s);

void foo(STRING* s1, STRING* s2)
{
STRING* s3 = string_concat(s1, s2);

string_free(s3);
}

void bar(STRING* s1, STRING* s2)
{
*s2 = *s1; // can't do that
}

$ cc -std=c11 -Wall -pedantic -c opaque.c
opaque.c: In function ‘bar’:
opaque.c:17:9: error: invalid use of incomplete typedef ‘STRING’ {aka
‘struct string_t’}
17 | *s2 = *s1;
| ^
opaque.c:17:7: error: invalid use of incomplete typedef ‘STRING’ {aka
‘struct string_t’}
17 | *s2 = *s1;
| ^

olcott

unread,
Apr 18, 2021, 5:04:34 PM4/18/21
to
I always took the same sort of approach. If you stick with the most
important subset of C++ the standard template library and the ability to
define self-contained objects, then C++ can greatly reduce the
complexity of programming tasks.

Because of the tediousness of memory allocation errors I only used fixed
length arrays in C, and I only use std::vector in C++. In several
decades as a professional programmer I have never allocated memory in C
or C++.

--
Copyright 2021 Pete Olcott

"Great spirits have always encountered violent opposition from mediocre
minds." Einstein

Bonita Montero

unread,
Apr 18, 2021, 5:31:39 PM4/18/21
to
> Where does that misconception come from?

That isn't a misconception.

Ben Bacarisse

unread,
Apr 18, 2021, 8:37:04 PM4/18/21
to
C++ includes almost all of those. And it throws a few more bits and
pieces into to mix (&, &&, pointer-to-member and so on).

--
Ben.

Juha Nieminen

unread,
Apr 19, 2021, 3:18:30 AM4/19/21
to
In comp.lang.c++ Manfred <non...@add.invalid> wrote:
> If the struct is opaque, the compiler won't allow you to assign a STRING
> object to another, as a start. In fact it won't allow to perform /any/
> operation on the object, except through the API that you define.

I see no difference between your scheme and mine.

String str1 = String_with_cstr("hello");
String str2 = str1;
// lots of code here
String_free(str1);
String_free(str2); // oops

vs.

String* str1 = String_with_c_str("hello");
String* str2 = str1;
// lots of code here
String_free(str1);
String_free(str2); // oops

> You can still mess up with pointers, but if you want to use C, then you
> have to know better.

My point is that for a beginner it's so much simpler to be able to do:

std::string str1 = "hello";
std::string str2 = str1;
// lots of code here
// no need to even destroy those strings, they'll be destroyed
// automatically

It's also significantly easier to try to guide a beginner to create a small
project like I described.

(Sure, you can start arguing about the efficiency issues of std::string
always making a deep copy whenever it's passed around, but this is just
trying to guide a beginner to do one of his first projects. The efficiency
questions can come up much, much later in the learning process. At this
point the efficiency issues are completely irrelevant.)

Juha Nieminen

unread,
Apr 19, 2021, 3:20:06 AM4/19/21
to
I was not commenting on the complexity of C++. I was commenting on the
claim that C is "very easy to understand".

No, it's not. Not in all cases, even when we aren't dealing with deliberately
obfuscated code.

Juha Nieminen

unread,
Apr 19, 2021, 3:22:55 AM4/19/21
to
olcott <No...@nowhere.com> wrote:
> Because of the tediousness of memory allocation errors I only used fixed
> length arrays in C, and I only use std::vector in C++. In several
> decades as a professional programmer I have never allocated memory in C
> or C++.

That's not always something you can avoid. Sometimes you need to, for example,
read an entire file into RAM. You can't just go and use a fixed-length
array for that.

(Just reading an entire file into RAM and doing something basig to it is
simple enough in C. However, it starts becoming complicated once you need
to start modifying parts of it such that they will grow larger. Like
inserting things into lines of text.)

MrSpook_w...@solbi8e3oaumg9.gov.uk

unread,
Apr 19, 2021, 3:42:46 AM4/19/21
to
On Sun, 18 Apr 2021 16:30:13 +0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
>MrSpook_wb@g9b2a_ex9aicgvs04.net wrote:
>> On Sat, 17 Apr 2021 05:56:42 +0000 (UTC)
>> Juha Nieminen <nos...@thanks.invalid> wrote:
>>>It quite quickly turned very frustrating for *both* of us that dynamic
>>>string manipulation in C is so damn complicated, especially for a
>>>complete beginner who has never programmed in C, and has only very
>>>little experience even with other programming languages (he had some
>>>very small experience with Python.)
>>
>> Umm, asprintf()
>
>Use a non-standard-C non-posix compiler extension for... what, exactly?

Its a defacto function standard found on Linux, BSD and MacOS and thats good
enough for me.

>Doesn't help one bit with allocation and deallocation of string
>objects.

Sorry? Allocation of the correct size string for the format is its raison
d'etre!

>If you are going to suggest functions that are not part of the
>standard language, you could just as well recommend using Python
>or something.

Sockets arn't part of the standard language so how would you suggest solving
networking issues using the language? Inline assembler?

>> Any powerful language is hard to learn at the start. Try telling a beginner
>> about C++ virtual function overloading or templates and watch the blank
>> expression appear.
>
>Why? He wanted to make a simple text editor, which manipulates dynamically
>allocated strings. What do virtual functions or templates have anything
>to do with this?

*sigh* It helps if you read whats been written before replying.

Ben Bacarisse

unread,
Apr 19, 2021, 6:36:38 AM4/19/21
to
Juha Nieminen <nos...@thanks.invalid> writes:

> Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
>> Juha Nieminen <nos...@thanks.invalid> writes:
>>
>>> Bonita Montero <Bonita....@gmail.com> wrote:
>>>> Of course C is a very simple language, i.e. the language itself is very
>>>> easy to understand.
>>>
>>> Where does that misconception come from?
>>>
>>> Even many experienced C programmers will have difficulty in understanding eg.
>>> the most complex function and array pointers, or even remember their syntax
>>> (there's a reason why sites like cdecl.org exist.)
>>
>> C++ includes almost all of those. And it throws a few more bits and
>> pieces into to mix (&, &&, pointer-to-member and so on).
>
> I was not commenting on the complexity of C++. I was commenting on the
> claim that C is "very easy to understand".

Ah, sorry. It would have been a bit clearer (since the discussion was
comparative) to say that both C and C++ have complex declaration syntax.

I get that you were countering the misconception that C is "very easy to
understand". Maybe you simply took it for granted that C++ wasn't very
easy to understand and it didn't need to mentioned.

> No, it's not. Not in all cases, even when we aren't dealing with deliberately
> obfuscated code.

The usual advice, in both languages, is not to use the available syntax.

--
Ben.

wij

unread,
Apr 19, 2021, 9:43:52 AM4/19/21
to
Once upon a time, C++ claimed being a superior system programming language.
Luckily, Linus Torvalds was not fooled as most C++ beginners were.
Such kind of topic (like, C/C++ which one is better) had been heavily discussed
several times before, in ways like debating which religion is better.
Just do not be overly zealous.

olcott

unread,
Apr 19, 2021, 10:50:59 AM4/19/21
to
On 4/19/2021 2:22 AM, Juha Nieminen wrote:
> olcott <No...@nowhere.com> wrote:
>> Because of the tediousness of memory allocation errors I only used fixed
>> length arrays in C, and I only use std::vector in C++. In several
>> decades as a professional programmer I have never allocated memory in C
>> or C++.
>
> That's not always something you can avoid. Sometimes you need to, for example,
> read an entire file into RAM. You can't just go and use a fixed-length
> array for that.
>

I read it into a std::vector that has its capacity set to the file size.

> (Just reading an entire file into RAM and doing something basig to it is
> simple enough in C. However, it starts becoming complicated once you need
> to start modifying parts of it such that they will grow larger. Like
> inserting things into lines of text.)
>


Bonita Montero

unread,
Apr 19, 2021, 10:54:39 AM4/19/21
to
> I was not commenting on the complexity of C++. I was commenting on the
> claim that C is "very easy to understand".
> No, it's not. Not in all cases, even when we aren't dealing with deliberately
> obfuscated code.

What I said wasn't related to actual code. Code could be
hard to understand also in even simpler languages like
Java. But the rules of the language are almost completely
easy to understand.

Manfred

unread,
Apr 19, 2021, 11:15:37 AM4/19/21
to
On 4/19/2021 9:18 AM, Juha Nieminen wrote:
> In comp.lang.c++ Manfred <non...@add.invalid> wrote:
>> If the struct is opaque, the compiler won't allow you to assign a STRING
>> object to another, as a start. In fact it won't allow to perform /any/
>> operation on the object, except through the API that you define.
>
> I see no difference between your scheme and mine.
>
> String str1 = String_with_cstr("hello");
> String str2 = str1;
> // lots of code here
> String_free(str1);
> String_free(str2); // oops
>
> vs.
>
> String* str1 = String_with_c_str("hello");
> String* str2 = str1;
> // lots of code here
> String_free(str1);
> String_free(str2); // oops

I do see a difference there, and it is the tiny little '*' in
> String* str2 = str1;

Which means that you are duplicating a pointer to an object and this
should trigger extra attention wrt object lifetime (and other things for
that matter).
Would you ever write with any lightness:
FILE* f1 = fopen("foo", "r");
FILE* f2 = f1;
// ...

If you want to use C you should get trained to this kind of details.
However, I get that this is probably what you mean by C being not simple
- it is not.
My point is that if you are using C, and you are familiar with it, then
there is a difference between the two designs.

(An example where your design is perfectly OK and widely used:
typedef struct point_t
{
int x;
int y;
} POINT;

POINT p1 = {42, 42};
POINT p2 = p1;
...

But here you make sure that the type is safely (trivially) copyable, a.o.)

>
>> You can still mess up with pointers, but if you want to use C, then you
>> have to know better.
>
> My point is that for a beginner it's so much simpler to be able to do:
>
> std::string str1 = "hello";
> std::string str2 = str1;
> // lots of code here
> // no need to even destroy those strings, they'll be destroyed
> // automatically
>
> It's also significantly easier to try to guide a beginner to create a small
> project like I described.

I'd comment about the term "easy" - you still need to know how RAII and
stuff works here, even if it all happens automatically.
I'd say that the fact that it happens behind the scenes might even make
it harder for a beginner.
The code /looks/ simpler, the mechanics of it is not - C++ is not simple
either.

Considering C++ simple is a major source of mistakes, IMO.

>
> (Sure, you can start arguing about the efficiency issues of std::string
> always making a deep copy whenever it's passed around, but this is just
> trying to guide a beginner to do one of his first projects. The efficiency
> questions can come up much, much later in the learning process. At this
> point the efficiency issues are completely irrelevant.)
>

Agreed, performance has no relevance here.

jacobnavia

unread,
Apr 19, 2021, 1:05:45 PM4/19/21
to
Le 19/04/2021 à 16:50, olcott a écrit :
> I read it into a std::vector that has its capacity set to the file size.

char *FileToRam(FILE *input)
{
fseek(f,0,SEEK_END);
long size = ftell(f);
fseek(f,0,SEEK_SET);
char *result = malloc(1+size));
if (result) {
fread(result,1,size,f);
result[size]=0;
}
return result;
}

No error checking, it is not very difficult to add it.

Another interface:

char *FileToRam(char *filename)
{
FILE *f = fopen(filename,"rb");

if (!f) return NULL;
fseek(f,0,SEEK_END);
long size = ftell(f);
fseek(f,0,SEEK_SET);
char *result = malloc(1+size));
if (result) {
fread(result,1,size,f);
result[size]=0;
}
return result;
}

Is C unreadable? Too complicated? I guess not!

olcott

unread,
Apr 19, 2021, 1:24:14 PM4/19/21
to
If you read the input a std::vector that has had its size set to the
file size then you can forget about the dynamic allocation of memory and
there will never be any memory leaks.

This single fact makes C++ simpler than C. In the decades that I have
been a C++ programmer I only use the standard template library and C++
classes and studiously ignore all of the rest of C++.

Self-contained classes eliminate scads of side-effects making them
impossible, thus greatly reducing the time that it take for ongoing
maintenance of a system, and greatly reducing overall system costs.

Linus Torvalds issues with C++ can be eliminated by coding standards
that make the otherwise hidden execution time costs of OOP utterly
visible. If we simply consider C++ as C with classes and a stanard
template library (the way that I do) his objections go away.

Scott Lurndal

unread,
Apr 19, 2021, 2:02:29 PM4/19/21
to
jacobnavia <ja...@jacob.remcomp.fr> writes:
>Le 19/04/2021 à 16:50, olcott a écrit :
>> I read it into a std::vector that has its capacity set to the file size.
>
>char *FileToRam(FILE *input)
>{
> fseek(f,0,SEEK_END);
> long size = ftell(f);
> fseek(f,0,SEEK_SET);
> char *result = malloc(1+size));
> if (result) {
> fread(result,1,size,f);
> result[size]=0;
> }
> return result;
>}
>
>No error checking, it is not very difficult to add it.

mmap is even easier since you don't need to allocate memory.

Bo Persson

unread,
Apr 19, 2021, 2:19:23 PM4/19/21
to
On 2021-04-19 at 15:43, wij wrote:
> On Monday, 19 April 2021 at 00:26:07 UTC+8, Juha Nieminen wrote:
>> wij <wyn...@gmail.com> wrote:
>>> One reason C programmer do not like C++ is C++ does things in the background
>>> Good or bad? not easy to say shortly.
>> I can't think of many things that C++ "does in the background". Perhaps the
>> most prominent (and perhaps the most controversial) thing is exceptions.
>> However, even then, originally exceptions were accepted into the first C++
>> standard only if it could be proven that they could be implemented "for
>> free" (ie. exception support would not slow down the program in any way
>> if exceptions are not thrown). It's my understanding that the standardization
>> committee was satisfied enough with the techniques that were possible and
>> accepted them.
>>
>> Of course one could also argue that RAII and compiler-generated constructors
>> and assignment operators are things that the compiler does "in the
>> background", but I would argue those are only beneficial, not detrimental.
>> And most importantly, they rarely come as a surprise to the programmer.
>> RAII certainly makes many things simpler (like in this example.)
>>
>> (Rather obviously the standard library doesn't really count as "C++ doing
>> things in the background" because else you could make the same argument
>> from the C standard library.)
>
> Once upon a time, C++ claimed being a superior system programming language.
> Luckily, Linus Torvalds was not fooled as most C++ beginners were.

That was more of a self-fullfilling prophecy on Linus' side.

Unfortunately for Linus, he was apparently presented with some C++ code
from these C++ beginners. And he saw that it was bad. And the blamed it
on the language. And not in a nice way either.

To quote http://harmful.cat-v.org/software/c++/linus

"*YOU* are full of bullshit.

C++ is a horrible language. It's made more horrible by the fact that a
lot of substandard programmers use it, to the point where it's much much
easier to generate total and utter crap with it. Quite frankly, even if
the choice of C were to do *nothing* but keep the C++ programmers out,
that in itself would be a huge reason to use C.

In other words: the choice of C is the only sane choice. I know Miles
Bader jokingly said "to piss you off", but it's actually true. I've come
to the conclusion that any programmer that would prefer the project to
be in C++ over C is likely a programmer that I really *would* prefer to
piss off, so that he doesn't come and screw up any project I'm involved
with."


And so he *did* piss of all competent C++ users, who didn't care to show
him what their good code looks like.





jacobnavia

unread,
Apr 19, 2021, 3:03:53 PM4/19/21
to
Mmmmmm I am ashamed to acknowledge that I did not close the file in the
second example. I saw it after posting. Sorry

wij

unread,
Apr 19, 2021, 4:04:41 PM4/19/21
to
To add more from the link:
------------------------------
In other words, the only way to do good, efficient, and system-level and
portable C++ ends up to limit yourself to all the things that are
basically available in C. And limiting your project to C means that people
don't screw that up, and also means that you get a lot of programmers that
do actually understand low-level issues and don't screw things up with any
idiotic "object model" crap.
------------------------------

I read (just impression in my head, I am not a English speaker) another
reason Linus Torvalds complained about C++ was something about
'interface' issues, difficult to unite codes from different groups
(guess: each has their owe smart idea, back then).

olcott

unread,
Apr 19, 2021, 4:14:35 PM4/19/21
to
In the above example using a C++ std::vector that is resized to the size
of the input file does make memory leaks utterly impossible.

Making memory leaks utterly impossible is a substantially more reliable
paradigm than allowing possible memory leaks to exist.

It is possible to gain this one single benefit of C++ and totally ignore
every other aspect of C++ by simply writing programs using the same C
style, yet compile them as c++ programs with a ".cpp" suffix.

Many C programmers do not switch to c++ because of the learning curve.

By focusing on a tiny subset of c++ (a) the standard template library
and (b) encapsulating data and functions together in classes, 90% of the
benefit of c++ can be achieved with a tiny little learning curve cost.

I started programming in C when K&R was the only standard.

Chris M. Thomasson

unread,
Apr 19, 2021, 8:16:55 PM4/19/21
to
On 4/19/2021 10:05 AM, jacobnavia wrote:
> Le 19/04/2021 à 16:50, olcott a écrit :
>> I read it into a std::vector that has its capacity set to the file size.
>
> char *FileToRam(FILE *input)
> {
>     fseek(f,0,SEEK_END);
>     long size = ftell(f);
>     fseek(f,0,SEEK_SET);
>     char *result = malloc(1+size));
>     if (result) {
>         fread(result,1,size,f);
>         result[size]=0;

Why are you zero terminating this? Is the files contents meant to be
used as a C string?


>     }
>     return result;
> }
[...]

Juha Nieminen

unread,
Apr 20, 2021, 12:02:46 AM4/20/21
to
wij <wyn...@gmail.com> wrote:
> Once upon a time, C++ claimed being a superior system programming language.
> Luckily, Linus Torvalds was not fooled as most C++ beginners were.

Almost nothing of what Linux wrote in that idiotic rant was true even back
when it was written, much less now.

Perhaps the most idiotic idea in his rant is the idea that C somehow
magically and automatically leads people to write good and efficient
code. No need to even explain how that's even possible.

Juha Nieminen

unread,
Apr 20, 2021, 12:05:43 AM4/20/21
to
In comp.lang.c++ Manfred <non...@add.invalid> wrote:
>> My point is that for a beginner it's so much simpler to be able to do:
>>
>> std::string str1 = "hello";
>> std::string str2 = str1;
>> // lots of code here
>> // no need to even destroy those strings, they'll be destroyed
>> // automatically
>>
>> It's also significantly easier to try to guide a beginner to create a small
>> project like I described.
>
> I'd comment about the term "easy" - you still need to know how RAII and
> stuff works here, even if it all happens automatically.
> I'd say that the fact that it happens behind the scenes might even make
> it harder for a beginner.

Might make *what* harder for a beginner, exactly?

Chris M. Thomasson

unread,
Apr 20, 2021, 12:42:29 AM4/20/21
to
On 4/17/2021 10:12 AM, Manfred wrote:
> (cross-posting to comp.lang.c to let the heat fire up)
>
> On 4/17/2021 7:56 AM, Juha Nieminen wrote:
>> I know that this is probably going to piss off avid C programmers,
>> but I don't really care all that much.
>
> Excellent start
>
> [...]
>>
>> I myself happen to know both languages quite well, and in fact I
>> program in both languages as my profession, and I would say that
>> I am very knowledgeable and proficient in both languages and have
>> no trouble in developing in either one. I am of the strong opinion
>> that no, C is not a "simple" language, and that C++ makes so many
>> things so much simpler, easier and safer.
>>
>> I was reminded of this in a quite concrete manner recently when I was
>> trying to help a beginner programmer who had decided to try his hands
>> on C, and wanted to create a simple text editor, which would read a
>> text file, allow the user to edit the text in several ways, and to
>> save the file.
>>
>> It quite quickly turned very frustrating for *both* of us ...
>
> The first comment that comes to mind is that probably part of the
> frustration stems from your approach (no offense) to try and use in C a
> design that would be suitable for C++ instead. Despite their name, the
> two are quite different languages. The similarities are about their
> runtime footprint, not about how they are used.
>
> For example, at a first glance the design of string object is not that
> great for C.
> A common pattern that pops to the mind is to use opaque structs (see
> e.g. FILE*), and have something like:
>
> typedef struct string_t STRING;
>
> STRING* alloc_string(); // creates the empty string
> STRING* set_string(STRING* s, const char* value);
> void free_string(STRING* s);
> STRING* concat_string(STRING* s1, STRING* s2);
> ...
>
> This way there would be no ambiguity about how the STRING object has to
> be used.
> And yes, in C you have to do all yourself - C is a low level language,
> and it is meant for low level stuff. It is hardly the right tool for
> anything meant to interface with a human user - it is (still) great for
> system programming and back-end processing, IMO.
>
> As second, I agree with Jacob that a text editor is a simple tool, but
> it is not easy to make expecially for a beginner.
>
>
> [snip]

I would not call C easy. Instead, I would refer to it as being more to
"the point", perhaps? Things have to be "explicit", it can be more
verbose. I say that because C does not have RAII. Also, C is really nice
to create plugins wrt creating portable bindings to other languages.
Usually in C, things tend go like the following when coding up a new
"object", so to speak:

Typing in the newsreader, sorry for typos.
________________________________

#include <stdio.h>
#include <stdlib.h>


struct foo
{
int a;
void* mem;
};

int foo_create(struct foo* const self)
{
if ((self->mem = malloc(sizeof(42))))
{
self->a = 84;
printf("foo_create(%p)\n", (void*)self);
return 1;
}

return 0;
}

void foo_destroy(struct foo const* const self)
{
printf("foo_destroy(%p)\n", (void*)self);
free(self->mem);
}

void foo_output(struct foo const* self, FILE* output)
{
printf("foo_output(%p)\n", (void*)self);
fprintf(output, "struct foo(%p)->a = %d\n", (void*)self, self->a);
fprintf(output, "struct foo(%p)->mem = %p\n", (void*)self, self->mem);
}


int main()
{
struct foo foo;

if (foo_create(&foo))
{
foo_output(&foo, stdout);

foo_destroy(&foo);
}

return 0;
}
________________________________


See how I have to make an explicit call to foo_destroy? This can be
handled in C++ in a "cleaner/safer" manner. Again, typing in the
newsreader sorry for typos. This would be a simple C++ wrapper to the C
API above:
________________________________

struct foo_wrapper
{
struct foo m_foo;

foo_wrapper() { if (! foo_create(&m_foo)) throw; }
~foo_wrapper() { foo_destroy(&m_foo); }

void output(FILE* output_) const
{
foo_output(&m_foo, output_);
}
};

________________________________

Then we can go:

{
foo_wrapper foo;
foo.output(stdout);
}

There. If it fails to create a foo in foo_create, it throws. Otherwise,
foo_destroy is guaranteed to be called when foo goes out of scope. So,
C++ can be more convenient, and safer. No need to use all of C++, but it
does have its moments.

Juha Nieminen

unread,
Apr 20, 2021, 12:56:34 AM4/20/21
to
wij <wyn...@gmail.com> wrote:
> Such kind of topic (like, C/C++ which one is better) had been heavily discussed
> several times before, in ways like debating which religion is better.
> Just do not be overly zealous.

The thing that prompted me to vent my frustrations in this thread was, as
I mentioned in my original post, a recent attempt at helping a beginner
who wanted to learn C.

It's hard to convey the difficulty and frustration trying to do this,
during the several days of trying to explain things and teach a good
proper approach at this type of C development, especially given the
kind of project that this person was trying to create (ie. a simple
text editor that loads a text file and allows the user to make
edits to it).

During the ordeal I just couldn't help but to think, and to comment
several times, how utterly and radically easier the very things he
was trying to do would be in C++, using std::string and std::vector.
(But he wanted to learn C specifically, I'm not sure exactly why.)
It was not only difficult to try to explain how dynamic memory
allocation works in C, and how such string manipulation should be
approached, but also it was difficult to explain *why* it should
be approached like that (ie. the idea of creating a more abstract
reusable "module" for handling dynamically allocated strings).

I would have been able to write such a program, but it was very difficult
to teach a complete beginner to do so (other than just giving all the
code readymade, which kind of defeats the purpose).

This whole thing just reminded me of *why* I dislike C so much. Sometimes,
even oftentimes, doing things that are extraordinarily simple in other
languages (such as C++) are really laborious and error-prone in C,
and require a level of knowledge, understanding and care that in
general you don't need in those other languages.

This is not the first time that pretty much this exact thing has happened
to me. It was merely the latest reminder and refresher.

jacobnavia

unread,
Apr 20, 2021, 1:32:39 AM4/20/21
to
Maybe. This utility doesn't NEED to know the usage, and zero terminating
it allows to use it as a string if the client code needs to. The cost is
completely negligible (writing zero to a byte).

>
>>      }
>>      return result;
>> }
> [...]

Chris M. Thomasson

unread,
Apr 20, 2021, 2:47:43 AM4/20/21
to
On 4/19/2021 10:32 PM, jacobnavia wrote:
> Le 20/04/2021 à 02:16, Chris M. Thomasson a écrit :
>> On 4/19/2021 10:05 AM, jacobnavia wrote:
>>> Le 19/04/2021 à 16:50, olcott a écrit :
>>>> I read it into a std::vector that has its capacity set to the file
>>>> size.
>>>
>>> char *FileToRam(FILE *input)
>>> {
>>>      fseek(f,0,SEEK_END);
>>>      long size = ftell(f);
>>>      fseek(f,0,SEEK_SET);
>>>      char *result = malloc(1+size));
>>>      if (result) {
>>>          fread(result,1,size,f);
>>>          result[size]=0;
>>
>> Why are you zero terminating this? Is the files contents meant to be
>> used as a C string?
>>
>
> Maybe. This utility doesn't NEED to know the usage, and zero terminating
> it allows to use it as a string if the client code needs to.

Okay. I see.


> The cost is
> completely negligible (writing zero to a byte).

I can think of a pretty hardcore nitpick. Think of a space constrained
client system that has very strict structured memory usage. Say it
forces your FileToRam function to use its own special malloc/free where
everything is aligned and padded to cache lines. So, that 1 byte of over
allocation can make malloc allocate a whole extra cache line! ;^)

The user wants to load a file that is 32 cache lines in size. Therefore,
it wants to allocate exactly 32 cache lines of memory, no more, no less.
However, you add that extra byte and force malloc to actually allocate
33 cache lines instead.

Sorry for the ultra hardcore nitpick. ;^o


>
>>
>>>      }
>>>      return result;
>>> }
>> [...]
>

Juha Nieminen

unread,
Apr 20, 2021, 6:29:53 AM4/20/21
to
jacobnavia <ja...@jacob.remcomp.fr> wrote:
> char *FileToRam(FILE *input)

By the way, it's always a good idea to use clear names that convey what
the function is doing, especially when we are talking about a C function
that does something like this. Optimally code would be self-documenting.

I think a declaration like this better conveys what the function does,
and that the calling code is responsible for freeing the return value:

char* allocByteArrayWithContentsOfFile(FILE* input);

Or, if you prefer:

char* alloc_byte_array_with_contents_of_file(FILE* input);

The "alloc" at the beginning better conveys that this is, indeed, an
allocation function and that the returned pointer points to something that
needs to be freed. (In C++ one usually doesn't need to convey this because,
usually, you would use as return value an object that itself manages the
allocated memory.)

It's also quite customary in C for such functions to return a success/error
code, instead of the allocated array. While not universal, you see this
quite a lot in C. So, perhaps, it could be like:

int alloc_byte_array_with_contents_of_file(FILE* input, char** dest);

Different return values can then be used to convey different types of error
(such as an error reading or seeking the file, or allocating the array).

jacobnavia

unread,
Apr 20, 2021, 8:14:44 AM4/20/21
to
Le 20/04/2021 à 12:29, Juha Nieminen a écrit :
> jacobnavia <ja...@jacob.remcomp.fr> wrote:
>> char *FileToRam(FILE *input)
>
> By the way, it's always a good idea to use clear names that convey what
> the function is doing, especially when we are talking about a C function
> that does something like this. Optimally code would be self-documenting.
>
> I think a declaration like this better conveys what the function does,
> and that the calling code is responsible for freeing the return value:
>
> char* allocByteArrayWithContentsOfFile(FILE* input);
>
> Or, if you prefer:
>
> char* alloc_byte_array_with_contents_of_file(FILE* input);
>

I agree that code should be self documenting BUT... the risk of
extremely long names as you propose is that you make a typo somewhere or
that users fed up with typing again and again such long names go to

#define readit(a) alloc_byte_array_with_contents_of_file(a)


> The "alloc" at the beginning better conveys that this is, indeed, an
> allocation function and that the returned pointer points to something that
> needs to be freed. (In C++ one usually doesn't need to convey this because,
> usually, you would use as return value an object that itself manages the
> allocated memory.)
>

Since the result is a char array with the contents of the file, and the
function taks only 1 input, it is obvious that the copntents are
allocated...

> It's also quite customary in C for such functions to return a success/error
> code, instead of the allocated array. While not universal, you see this
> quite a lot in C. So, perhaps, it could be like:
>
> int alloc_byte_array_with_contents_of_file(FILE* input, char** dest);

Note that the function returns NULL in case of failure. This is very
common in C.
>
> Different return values can then be used to convey different types of error
> (such as an error reading or seeking the file, or allocating the array).
>

Yeah, but this is more concise, and supposes that you do not care about
what really happened, just that it didn't work.


wij

unread,
Apr 20, 2021, 8:22:37 AM4/20/21
to
On Tuesday, 20 April 2021 at 12:56:34 UTC+8, Juha Nieminen wrote:
> wij <wyn...@gmail.com> wrote:
> > Such kind of topic (like, C/C++ which one is better) had been heavily discussed
> > several times before, in ways like debating which religion is better.
> > Just do not be overly zealous.
> The thing that prompted me to vent my frustrations in this thread was, as
> I mentioned in my original post, a recent attempt at helping a beginner
> who wanted to learn C.
>
> It's hard to convey the difficulty and frustration trying to do this,
> during the several days of trying to explain things and teach a good
> proper approach at this type of C development, especially given the
> kind of project that this person was trying to create (ie. a simple
> text editor that loads a text file and allows the user to make
> edits to it).
>

Those are common problems to teach that kind level of C beginners.
Nothing to surprise or be frustrated.

A minimal functional text editor (like nano) is not simple from ground up.
I do not think using 'pure' C++ (Smart Macro Library or STL) can do the
job 'elegantly' and 'efficiently', as well as numerous system commands,
with respect to using C.

> During the ordeal I just couldn't help but to think, and to comment
> several times, how utterly and radically easier the very things he
> was trying to do would be in C++, using std::string and std::vector.
> (But he wanted to learn C specifically, I'm not sure exactly why.)
> It was not only difficult to try to explain how dynamic memory
> allocation works in C, and how such string manipulation should be
> approached, but also it was difficult to explain *why* it should
> be approached like that (ie. the idea of creating a more abstract
> reusable "module" for handling dynamically allocated strings).
>
> I would have been able to write such a program, but it was very difficult
> to teach a complete beginner to do so (other than just giving all the
> code readymade, which kind of defeats the purpose).
>
> This whole thing just reminded me of *why* I dislike C so much. Sometimes,
> even oftentimes, doing things that are extraordinarily simple in other
> languages (such as C++) are really laborious and error-prone in C,
> and require a level of knowledge, understanding and care that in
> general you don't need in those other languages.
>
> This is not the first time that pretty much this exact thing has happened
> to me. It was merely the latest reminder and refresher.

If we were talking some example programs from some C++ book, I have no comment.

Manfred

unread,
Apr 20, 2021, 12:27:36 PM4/20/21
to
Anything that happens behind the scenes and the compiler "does it for
you" does require knowledge by the programmer about something they don't
see and yet they must be aware of and know how it works.
And yes, they are intended to (and actually do) make life easier for the
programmer /after/ they master their mechanics, but a beginner's mistake
related with such hidden features is likely to lead to somewhat
shady/obscure bugs - i.e. hard for said beginner.

On a different perspective, consider e.g. rvalue refs and "universal"
refs (in Meyers' terms) - they make a useful feature, but good luck
explaining it to said beginner.

Juha Nieminen

unread,
Apr 20, 2021, 12:41:45 PM4/20/21
to
In comp.lang.c++ Manfred <non...@add.invalid> wrote:
> Anything that happens behind the scenes and the compiler "does it for
> you" does require knowledge by the programmer about something they don't
> see and yet they must be aware of and know how it works.
> And yes, they are intended to (and actually do) make life easier for the
> programmer /after/ they master their mechanics, but a beginner's mistake
> related with such hidden features is likely to lead to somewhat
> shady/obscure bugs - i.e. hard for said beginner.

The problem with C is that anything that requires manual construction and
destruction will "contaminate" (can't think of a better word) anything that
uses that first thing, with the same requirements. All the way down.

If you have this kind of "string" object that requires manual construction
and destruction, and you put it as a member of a struct, suddenly that
struct "inherits" the same requirement. Use that struct in yet another
struct and that, too, will "inherit" the same requirement.

Moreover, suppose you have a complex hierarchy of structs as members of
other structs, no dynamic memory allocation in sight so far. Then you need
to add dynamic memory allocation to one of the structs (that's being used
as a member of other structs etc) and suddenly all that code breaks. If
there are millions of lines of code using any of those structs that have
now "inherited" the need for manual construction and destruction (even though
they were never designed for that initially), you'll have to go and modify
those millions of lines to follow suit.

The complexity can quickly grow exponentially.

Not so in C++, if you design your structs/classes correctly. Even if some
struct/class very deep in the dependency tree suddenly starts allocating
memory dynamically, that doesn't matter. None of the other structs/classes
that may be using it as their members need to be touched in any way. The
struct/class automatically takes care of its own memory management. You
don't need to go through the millions of lines of code to add support.

> On a different perspective, consider e.g. rvalue refs and "universal"
> refs (in Meyers' terms) - they make a useful feature, but good luck
> explaining it to said beginner.

I wouldn't teach function and array pointers as a first thing to a beginner.
Likewise I wouldn't teach rvalue references as a first thing.

Juha Nieminen

unread,
Apr 20, 2021, 12:45:12 PM4/20/21
to
jacobnavia <ja...@jacob.remcomp.fr> wrote:
>> char* alloc_byte_array_with_contents_of_file(FILE* input);
>
> I agree that code should be self documenting BUT... the risk of
> extremely long names as you propose is that you make a typo somewhere

Yeah. It's not like the compiler will give you an error message or anything.

> or
> that users fed up with typing again and again such long names go to
>
> #define readit(a) alloc_byte_array_with_contents_of_file(a)

That's their shame, not yours.

>> The "alloc" at the beginning better conveys that this is, indeed, an
>> allocation function and that the returned pointer points to something that
>> needs to be freed. (In C++ one usually doesn't need to convey this because,
>> usually, you would use as return value an object that itself manages the
>> allocated memory.)
>>
>
> Since the result is a char array with the contents of the file, and the
> function taks only 1 input, it is obvious that the copntents are
> allocated...

Not necessarily.

Does, for example, fopen() dynamically allocate the FILE object?
I have no idea. It's not at all obvious.

>> It's also quite customary in C for such functions to return a success/error
>> code, instead of the allocated array. While not universal, you see this
>> quite a lot in C. So, perhaps, it could be like:
>>
>> int alloc_byte_array_with_contents_of_file(FILE* input, char** dest);
>
> Note that the function returns NULL in case of failure. This is very
> common in C.

The problem is that with one single error value there's no way of knowing
*why* the function failed. That doesn't make it a very good function.

jacobnavia

unread,
Apr 20, 2021, 1:44:29 PM4/20/21
to
Le 20/04/2021 à 18:41, Juha Nieminen a écrit :
> The problem with C is that anything that requires manual construction and
> destruction will "contaminate" (can't think of a better word) anything that
> uses that first thing, with the same requirements. All the way down.
>
> If you have this kind of "string" object that requires manual construction
> and destruction, and you put it as a member of a struct, suddenly that
> struct "inherits" the same requirement. Use that struct in yet another
> struct and that, too, will "inherit" the same requirement.

No.

Just have a constructotr and never free anything. Then link with Boehm's
GARBAGE COLLECTOR and be done with it!

I have already said this in this thread but people will go on arguing
about how difficult is to keep the accounting of memory pieces right.

And they are right but refuse to see the right tool for theirpurpose:
just use a garbage collector and BE DONE WITH IT.

I use an automatic car, no passing of gears. Recently I spoke with a
taxi driver... "Don't you get bored passing gears all day?"

And he acknowledged: yes, My arm hurts at the end of the day. Maybe you
are right, should get an automatic...

Use an automatic garbage collector and BE DONE WITH IT. And please, do
not start with performance problems, in most string applications the gc
is completely transparent.


Alf P. Steinbach

unread,
Apr 20, 2021, 1:53:19 PM4/20/21
to
On 20.04.2021 18:41, Juha Nieminen wrote:
> In comp.lang.c++ Manfred <non...@add.invalid> wrote:
>> Anything that happens behind the scenes and the compiler "does it for
>> you" does require knowledge by the programmer about something they don't
>> see and yet they must be aware of and know how it works.
>> And yes, they are intended to (and actually do) make life easier for the
>> programmer /after/ they master their mechanics, but a beginner's mistake
>> related with such hidden features is likely to lead to somewhat
>> shady/obscure bugs - i.e. hard for said beginner.
>
> The problem with C is that anything that requires manual construction and
> destruction will "contaminate" (can't think of a better word) anything that
> uses that first thing, with the same requirements. All the way down.
>
> If you have this kind of "string" object that requires manual construction
> and destruction, and you put it as a member of a struct, suddenly that
> struct "inherits" the same requirement. Use that struct in yet another
> struct and that, too, will "inherit" the same requirement.
>
> Moreover, suppose you have a complex hierarchy of structs as members of
> other structs, no dynamic memory allocation in sight so far. Then you need
> to add dynamic memory allocation to one of the structs (that's being used
> as a member of other structs etc) and suddenly all that code breaks. If
> there are millions of lines of code using any of those structs that have
> now "inherited" the need for manual construction and destruction (even though
> they were never designed for that initially), you'll have to go and modify
> those millions of lines to follow suit.

Very good points.

In addition, what C++ provides as built-in language features, has to be
supplied as 3d party library or DIY functionality in C.

That means that in C

* one can't leverage a single knowledge base, but must learn each
support library that's needed for those C++ features, and
* the compiler can't be fine tuned to a particular implementation.



> The complexity can quickly grow exponentially.

Not sure about that though, but that it grows, yes.


> Not so in C++, if you design your structs/classes correctly. Even if some
> struct/class very deep in the dependency tree suddenly starts allocating
> memory dynamically, that doesn't matter. None of the other structs/classes
> that may be using it as their members need to be touched in any way. The
> struct/class automatically takes care of its own memory management. You
> don't need to go through the millions of lines of code to add support.
>
>> On a different perspective, consider e.g. rvalue refs and "universal"
>> refs (in Meyers' terms) - they make a useful feature, but good luck
>> explaining it to said beginner.
>
> I wouldn't teach function and array pointers as a first thing to a beginner.
> Likewise I wouldn't teach rvalue references as a first thing.

The "Accelerated C++" book by Andrew Koenig and Barbara Mooooooooo
showed that the high level approach can really work for C++.

But I think that for these fundamental aspects of programming, if one
desires to teach at a high level of abstraction then some other language
will be better suited. I'm thinking C# (which I known from the "classic"
C# days) or, say, Rust (which I don't know beyond "Hello, world!").

A nice feature of C++ is that it's /possible/ to teach programming in a
mixed way, introducing the low level stuff but using containers, strings
etc. It's sad that C++ still lacks standard 128-bit integers and ditto
currency type; still lacks datetime type; still lacks a practically
usable for beginners version of `std::ranges::views::iota` (I prefer to
define things so one can write e.g. `for( const int i: zero_to( n ) )`;
not to mention that the common /C++ implementations/ for Windows still
lack support for UTF-8, both in console and GUI programs, so that
learners can't even write a program that displays their non-English name
in Windows without using 3rd party libraries or the Windows API.

That's just basic functionality.

Try motivating a leaner by coding up the (recursive) C curve in standard
C++ only. Oh, no graphics. Oh well.

So, as I see it standard C++ in itself is not good for learners, but it
can be good with the right 3rd party libraries. I guess you all know
that I've been hobby-working on libraries to fill the mentioned data
type and console i/o voids, and that I've found that it decidedly is a
non-trivial design task (which may be part of the reason why such
libraries don't already exists). And perhaps the good Mr. Fibble's
Neo-something could help with the graphics and sound aspects.

- Alf

Kaz Kylheku

unread,
Apr 20, 2021, 2:30:44 PM4/20/21
to
On 2021-04-20, jacobnavia <ja...@jacob.remcomp.fr> wrote:
> Le 20/04/2021 à 18:41, Juha Nieminen a écrit :
>> The problem with C is that anything that requires manual construction and
>> destruction will "contaminate" (can't think of a better word) anything that
>> uses that first thing, with the same requirements. All the way down.
>>
>> If you have this kind of "string" object that requires manual construction
>> and destruction, and you put it as a member of a struct, suddenly that
>> struct "inherits" the same requirement. Use that struct in yet another
>> struct and that, too, will "inherit" the same requirement.
>
> No.
>
> Just have a constructotr and never free anything. Then link with Boehm's
> GARBAGE COLLECTOR and be done with it!

You are talking about a different nuance for construction.

In high level, dynamic languages, constructing an object refers to
aggregation.

The ancient function CONS in Lisp may hgave been the first one to use
the construction terminology. If we make a CONS which contains two
strings, there is not construction of those strings going on; they are
already constructed:

(cons "abc" "def")

Juha is probably talking about C++ style construction where if we have
struct foo { string s; foo(); }, the foo::foo constructor has to
call the string::string constructor.

Juha's remarks are true when objects are put together using composition
rather than aggregation.

Because the object B is embedded in another A, and must be initialized,
then the type-B-specific initialization logic for that embedded object
has to be invoked to initialize that B-typed portion of A.

From an abstraction point of view, it's really a shit design. But the
motivation is solid: there are certain efficiencies you can gain when
you compose rather than aggregate objects. You save space by not
allocating separate objects, reducing allocator overhead, and by not
allocating a pointer to navigate from one to the other. By not chasing a
pointer, you reduce pipeline stalls due to dependent loads. Low-level,
systems programming languages benefit from being able to compose
objects.

It's not worth trying to shoehorn that paradigm into a high level
language though. Composition of objects works for simple, low-level code
that has to run fast, and requires only a simple language.

If your idea for building a web browser or word processor includes
anything like this:

class Document {
std::string documentName;

//
}

due to the immense benefit of not having to chase an extra pointer
or allocate an extra object, you must be a supreme moron, and you will
have your lunch eaten by someone working in Javascript or Python.

> I have already said this in this thread but people will go on arguing
> about how difficult is to keep the accounting of memory pieces right.

> And they are right but refuse to see the right tool for theirpurpose:
> just use a garbage collector and BE DONE WITH IT.

That should be: use a language with a garbage collector and be done
with it.

Statistically/probabilistically speaking, given that you have a genuine
reason to be using C, then conditional probability is high that garbage
collection may not be a good fit for the problem.

> I use an automatic car, no passing of gears. Recently I spoke with a
> taxi driver... "Don't you get bored passing gears all day?"
>
> And he acknowledged: yes, My arm hurts at the end of the day. Maybe you
> are right, should get an automatic...
>
> Use an automatic garbage collector and BE DONE WITH IT. And please, do
> not start with performance problems, in most string applications the gc
> is completely transparent.

GC has good performance. But not in a small space. GC needs more memory
than manual freeing in order to perform well.

Most of the speed (in terms of raw throughput) improvements in GC
revolve around the theme of allowing garbage to linger around longer, so
that garbage cycles are either less frequent (e.g. tuning a larger
heap), or smaller in scope (generational GC, visiting just a young
subset of the object graph in most GC passes).

Allowing garbage to stick around longer translates to one thing: larger
memory footprints.

Adding GC to a simple, embedded application in which manual memory
management can be done correctly with relative ease will just bloat
its footprint. If the footprint is kept very tight, GC will run often
which could degrade the performance.

In a single-process system with physical memory, you can just
do collection whenever memory is nearly exausted, which is optimal.
The memory is needed for nothing else.

In a VM system that is using all of its free memory for a buffer/file
cache, any extra slack space for GC encroaches on that cache, even if no
other applications are running. Which they usually are. VM footprints
matter.

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

Richard Damon

unread,
Apr 20, 2021, 2:46:25 PM4/20/21
to
But that only works for a fungible resource like memory. If you really
need to release the resource right away (like a lock on something) you
really want RAII.

jacobnavia

unread,
Apr 20, 2021, 2:47:46 PM4/20/21
to
Le 20/04/2021 à 20:30, Kaz Kylheku a écrit :
> GC has good performance. But not in a small space. GC needs more memory
> than manual freeing in order to perform well.
>

Note: malloc/free do garbage collection by consolidating free memory
blocks into larger ones. This essential FACT is being overlooked here.

But granted, in small embedded applications with less CPU power and less
RAM GC is not the ideal solution and you do the accounting by hand. But
in those environments, C++ is anyway out of the question!

> Most of the speed (in terms of raw throughput) improvements in GC
> revolve around the theme of allowing garbage to linger around longer, so
> that garbage cycles are either less frequent (e.g. tuning a larger
> heap), or smaller in scope (generational GC, visiting just a young
> subset of the object graph in most GC passes).
>

See above. In small spaces GC is not that good. But we were talking
about a TEXT EDITOR for learning C, so that is probably a PC environment
where GC SHINES!

> Allowing garbage to stick around longer translates to one thing: larger
> memory footprints.
>

Yes. But you can obviate that by calling the GC explicitely from time to
time.

> Adding GC to a simple, embedded application in which manual memory
> management can be done correctly with relative ease will just bloat
> its footprint. If the footprint is kept very tight, GC will run often
> which could degrade the performance.
>

Agreed. As I said above, for simple, embedded applications the GC is not
the best solution.

> In a single-process system with physical memory, you can just
> do collection whenever memory is nearly exausted, which is optimal.
> The memory is needed for nothing else.
>
> In a VM system that is using all of its free memory for a buffer/file
> cache, any extra slack space for GC encroaches on that cache, even if no
> other applications are running. Which they usually are. VM footprints
> matter.

There are MANY other solutions in C. You can do pool allocating, for
instance, allocating all the related strings from a pool that is freed
in a single instruction. ETC.


Kaz Kylheku

unread,
Apr 20, 2021, 4:18:32 PM4/20/21
to
["Followup-To:" header set to comp.lang.c.]
RAII can be entirely separated from memory allocation. RAII can unlock
mutexes and close handles without invalidating memory.

I implemented a form of RAII in TXR Lisp.

This is the TXR Lisp interactive listener of TXR 256.
Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
If unwanted side effects persist, discontinue imperative programming.
1> (defstruct obj ()
(:init (me) (put-line `@me constructed`))
(:fini (me) (put-line `@me finalized`)))
#<struct-type obj>
2> (with-objects ((x (new obj)))
(put-line "inside with-objects"))
#S(obj) constructed
inside with-objects
#S(obj) finalized
t

The object has not gone away; just its finalizer was prematurely
invoked. When the object becomes garbage, that finalizer will not be
called any more; it is no longer registered for finalization.

If an exception goes off while an object is being initialized,
a similar thing happens:

TXR's no-spray organic production means every bug is carefully removed by hand.
1> (defstruct obj ()
(:init (me)
(put-line `@me constructed ... almost`)
(throw 'error))
(:fini (me) (put-line `@me finalized`)))
#<struct-type obj>
2> (new obj)
#S(obj) constructed ... almost
#S(obj) finalized
** exception args: nil
** during evaluation at expr-1:4 of form (throw 'error)
** run with --backtrace to enable backtraces

Struct objects have multiple finalizers at different levels of the
inheritance hierarchy; these get called in well-defined, documented
orders.

You can invoke an object's finalizers directly at any time with
(call-finalizers obj). Using that, and unwind-protect, you can
build your own scoping macros.

For something like acquiring and releasing a lock, we wouldn't
be constructing an object.

This is the problem in C++: RAII is strictly based on constructing and
destroying something, and always requires an object, and that must be a
class.

TXR Lisp offers a standard macro (based on unwind-protect under the hood)
for managing resources that can be allocated with expressions that
produce a value, and then disposed of by passing that value to another
expression. The value can be anything:

Use TXR only as directed. Unless you are intelligent, curious and creative.
1> (defun make-widget (arg)
(put-line `make-widget: @arg`)
arg)
make-widget
2> (defun break-widget (arg)
(put-line `break-widget: @arg`))
break-widget
3> (with-resources ((x (make-widget 42) (break-widget x))
(y (make-widget 'foo) (break-widget y)))
(put-line "inside with-resources"))
make-widget: 42
make-widget: foo
inside with-resources
break-widget: foo
break-widget: 42

Chris M. Thomasson

unread,
Apr 20, 2021, 4:19:48 PM4/20/21
to
On 4/20/2021 10:44 AM, jacobnavia wrote:
> Le 20/04/2021 à 18:41, Juha Nieminen a écrit :
>> The problem with C is that anything that requires manual construction and
>> destruction will "contaminate" (can't think of a better word) anything
>> that
>> uses that first thing, with the same requirements. All the way down.
>>
>> If you have this kind of "string" object that requires manual
>> construction
>> and destruction, and you put it as a member of a struct, suddenly that
>> struct "inherits" the same requirement. Use that struct in yet another
>> struct and that, too, will "inherit" the same requirement.
>
> No.
>
> Just have a constructotr and never free anything. Then link with Boehm's
> GARBAGE COLLECTOR and be done with it!

Wow! Really? Did you know that manual memory management can actually
help a GC'ed environment run more efficiently? I have had to deal with
questions about performance issues wrt using a garbage collector to act
as a memory reclamation scheme for lock-free algorithms for almost two
decades. GC can become a rather nasty, unpredictable, bottleneck.

Kaz Kylheku

unread,
Apr 20, 2021, 4:29:44 PM4/20/21
to
On 2021-04-20, Chris M. Thomasson <chris.m.t...@gmail.com> wrote:
> On 4/20/2021 10:44 AM, jacobnavia wrote:
>> Le 20/04/2021 à 18:41, Juha Nieminen a écrit :
>>> The problem with C is that anything that requires manual construction and
>>> destruction will "contaminate" (can't think of a better word) anything
>>> that
>>> uses that first thing, with the same requirements. All the way down.
>>>
>>> If you have this kind of "string" object that requires manual
>>> construction
>>> and destruction, and you put it as a member of a struct, suddenly that
>>> struct "inherits" the same requirement. Use that struct in yet another
>>> struct and that, too, will "inherit" the same requirement.
>>
>> No.
>>
>> Just have a constructotr and never free anything. Then link with Boehm's
>> GARBAGE COLLECTOR and be done with it!
>
> Wow! Really? Did you know that manual memory management can actually
> help a GC'ed environment run more efficiently? I have had to deal with
> questions about performance issues wrt using a garbage collector to act
> as a memory reclamation scheme for lock-free algorithms for almost two
> decades. GC can become a rather nasty, unpredictable, bottleneck.

Snip of a recent commit of mine:

commit 174182a29c785493ed41231caff36f35c56819cf
Author: Kaz Kylheku <k...@kylheku.com>
Date: Tue Apr 6 20:06:18 2021 -0700

gc: fix astonishing bug in weak hash processing.

This is a flaw that has been in the code since the initial
implementation in 2009.

:)

Chris M. Thomasson

unread,
Apr 20, 2021, 4:29:51 PM4/20/21
to
On 4/20/2021 11:47 AM, jacobnavia wrote:
> Le 20/04/2021 à 20:30, Kaz Kylheku a écrit :
>> GC has good performance. But not in a small space. GC needs more memory
>> than manual freeing in order to perform well.
>>
>
> Note: malloc/free do garbage collection by consolidating free memory
> blocks into larger ones. This essential FACT is being overlooked here.

consolidating smaller blocks into larger ones has nothing to do with the
conventional notion of a garbage collector. So, you saying that
malloc/free do GC is very odd to me, indeed.

Chris M. Thomasson

unread,
Apr 20, 2021, 4:39:35 PM4/20/21
to
Wow! I remember somebody asking me why the GC is under so much pressure.
They showed me their code where most of the allocations were coming
from. Of course they were allocating a new node for every push into a
lock-free stack! I said the simplest thing I could think of, just to see
if it made a difference... It was: Create a LIFO node cache, and create
a layered approach for allocating nodes. Try the cache first, then
resort to allocating a new node for now. The response was well, then we
have to use manual memory management for the node cache. I said, indeed
you do! So, they did it. Guess what? They were able to increase
performance by orders of magnitude! The GC had a lot less pressure on
it. Iirc, this was in Java. All due to good ol' manual memory management
even in a GC system.

Ian Collins

unread,
Apr 20, 2021, 4:56:45 PM4/20/21
to
On 21/04/2021 05:44, jacobnavia wrote:
> Le 20/04/2021 à 18:41, Juha Nieminen a écrit :
>> The problem with C is that anything that requires manual construction and
>> destruction will "contaminate" (can't think of a better word) anything that
>> uses that first thing, with the same requirements. All the way down.
>>
>> If you have this kind of "string" object that requires manual construction
>> and destruction, and you put it as a member of a struct, suddenly that
>> struct "inherits" the same requirement. Use that struct in yet another
>> struct and that, too, will "inherit" the same requirement.
>
> No.
>
> Just have a constructotr and never free anything. Then link with Boehm's
> GARBAGE COLLECTOR and be done with it!

Let's not forget that memory isn't the only resource that a program has
to manage.

--
Ian.

Chris M. Thomasson

unread,
Apr 20, 2021, 5:07:27 PM4/20/21
to
On 4/20/2021 10:44 AM, jacobnavia wrote:
For some reason, anytime I hear somebody go, just use a GC... Well, it
makes think of this song:

https://youtu.be/WJabPYimznY

Or the following scene in Disney's Dragonslayer from 1981:

https://youtu.be/TJRaLnLDMWg

Chris M. Thomasson

unread,
Apr 20, 2021, 5:29:52 PM4/20/21
to
For the life of me I cannot remember if this was using Java or C with
the Bohem collector.

Juha Nieminen

unread,
Apr 21, 2021, 12:37:31 AM4/21/21
to
In comp.lang.c++ jacobnavia <ja...@jacob.remcomp.fr> wrote:
> See above. In small spaces GC is not that good. But we were talking
> about a TEXT EDITOR for learning C, so that is probably a PC environment
> where GC SHINES!

If that's the case, then just use a language like Java or Python.

Or, you know, C++.

At least you won't be needing to use non-standard third-party extensions.

wij

unread,
Apr 21, 2021, 1:02:31 AM4/21/21
to
If that's the case, why you learn C/C++?
I feel your logic is similar to olcott's, maybe a bit worse.

wij

unread,
Apr 21, 2021, 1:35:13 AM4/21/21
to
By the way, I do not use most "standard" stuff, that enables me to gain more
functionality from "C", and much less unnecessary "standard" burdens.

Chris Vine

unread,
Apr 21, 2021, 1:30:12 PM4/21/21
to
On Tue, 20 Apr 2021 04:02:30 +0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
> wij <wyn...@gmail.com> wrote:
> > Once upon a time, C++ claimed being a superior system programming language.
> > Luckily, Linus Torvalds was not fooled as most C++ beginners were.
>
> Almost nothing of what Linux wrote in that idiotic rant was true even back
> when it was written, much less now.

I would say it has about the same validity as your own arguments about C
and how much easier C++ is for beginners (you came up with a similar
set of arguments about a year or so ago). Both languages are difficult
for beginners and require a high degree of skill to use well. On
balance I suspect C++ has a few more 'gotchas' because it is a more
complex language and does more things for you implicitly.

For what it is worth, Linus has now accepted Rust into the linux kernel
for certain (at present limited) purposes, principally I think because
of its linear/affine type system.

Scott Lurndal

unread,
Apr 21, 2021, 2:34:04 PM4/21/21
to
And linux aside, I've personally written two commercial operating systems and two
hypervisors in C++ since 1989. It works just fine for operating systems
_if you don't use the C++ library crap_. Don't use vectors, don't use maps,
don't use exceptions, don't use dynamic allocation. (use placement new
or pool-based page/slab/slub allocators).

You still get the benefits of data hiding/encapsulation, and compiler support
for what linux calls "ops vectors" (which are basically vtables).

I do think Linus is off base. However, it's a moot point as nobody
will ever rewrite linux in a new language. He does have a point about
the odd need for some C++ programmers to show off their expertise by using
every odd or unusual C++ feature.

class fs_vectors_t {
/* pure virtual (abstract) file system op vectors; e.g. lookup, create, open, close, delete, read, write */
}

class ext4_fs : public fs_vectors_t
{
...
}

class btrfs : public fs_vectors_t
{
...
}

Chris Vine

unread,
Apr 21, 2021, 4:14:27 PM4/21/21
to
[snip]

I go along with pretty much all of that. I suppose the calculation for
a putative kernel lead (here, Linus) is (i) whether, if you have
started out in C, it is worth moving to C++ (IOW, are the limited
additional features of C++ over C that you would be prepared to accept
in the kernel worth the change) and (ii) whether you trust open source
contributors to stick to that limited set without opening up potential
aggravation later. That might be easier in a closed-source environment
such as the one I presume you were working in.

The fact is that C is now a vastly smaller language than, say, C++20.

Of course, similar issues arise for including Rust in the kernel. It
will be interesting to see how it works out.

Chris M. Thomasson

unread,
Apr 21, 2021, 6:27:16 PM4/21/21
to
Fwiw, using an "extension" in C is nothing new. Want to create a server,
better learn how to use sockets. If you want to go deep, create your own
TCP stack. Is creating a driver in C to use a 3d party device "cheating"
by using third-party extensions? third-party API's?

Luckily for me a lot of my recent work is 100% workable with pure C and
graphics. Pure C generating a PPM image is absolutely perfect. 100%
portable and no 3d party code used in any way, shape or form. :^)

If the user wants to view the result of my C code, they can choose any
PPM viewer they want to. There, pure C code generating fractals, vector
fields, abstract art, ect. ;^)

Way back in the day I would be forced to use "extensions" to C. Things
like POSIX, Pthreads, my own externally assembled atomic's libs for
various archs using MASM and GAS, ect... I still have a bunch of code
that uses the good ol' Pthreads for win32 lib here:

https://sourceware.org/pthreads-win32

When C/C++ 11 made atomic's and threading standard, it was really nice,
but made me want to port all of my older code from Pthreads and assembly
language to the new stuff.

Here is a result of some of my C code generating a single file for
another program, PovRay, to raytrace for me:

https://youtu.be/skGUAXAx6eg

https://youtu.be/R0v_1EBAOr4

Chris M. Thomasson

unread,
Apr 21, 2021, 6:38:11 PM4/21/21
to
On 4/21/2021 11:33 AM, Scott Lurndal wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:
>> On Tue, 20 Apr 2021 04:02:30 +0000 (UTC)
>> Juha Nieminen <nos...@thanks.invalid> wrote:
>>> wij <wyn...@gmail.com> wrote:
>>>> Once upon a time, C++ claimed being a superior system programming language.
>>>> Luckily, Linus Torvalds was not fooled as most C++ beginners were.
>>>
>>> Almost nothing of what Linux wrote in that idiotic rant was true even back
>>> when it was written, much less now.
>>
>> I would say it has about the same validity as your own arguments about C
>> and how much easier C++ is for beginners (you came up with a similar
>> set of arguments about a year or so ago). Both languages are difficult
>> for beginners and require a high degree of skill to use well. On
>> balance I suspect C++ has a few more 'gotchas' because it is a more
>> complex language and does more things for you implicitly.
>>
>> For what it is worth, Linus has now accepted Rust into the linux kernel
>> for certain (at present limited) purposes, principally I think because
>> of its linear/affine type system.
>
> And linux aside, I've personally written two commercial operating systems and two
> hypervisors in C++ since 1989. It works just fine for operating systems
> _if you don't use the C++ library crap_. Don't use vectors, don't use maps,
> don't use exceptions, don't use dynamic allocation. (use placement new
> or pool-based page/slab/slub allocators).

Agreed!

wij

unread,
Apr 22, 2021, 1:06:43 AM4/22/21
to
When thread was introduced in C++11, I needed to consider using it or not, too.
But after weighing the gains and losses, I decided that RAII feature outweigh
the efficiency. Thus, not using it.
C++ has several places violated its original OO principle, this is just one example.
For instance, the added keyword override/final/delete (good, but it reflects the
half-true "object model" crap) violated the C++ author's ideal (or guideline) about a
a good language "...not add a new feature and then add another to disable it..."

> https://youtu.be/skGUAXAx6eg
>
> https://youtu.be/R0v_1EBAOr4

wij

unread,
Apr 22, 2021, 1:38:21 AM4/22/21
to
Yes, C++ fans often ignore the program size issue.
I used often to see C++ complied object file contain almost 1/2 entries
of name symbols, most of them are throw types, rare people care about.
When it comes to the kernel, the entire OS, even 1Gb would make me
worry the life-time of my disk.

Chris M. Thomasson

unread,
Apr 22, 2021, 3:27:01 AM4/22/21
to
On 4/19/2021 9:42 PM, Chris M. Thomasson wrote:
> On 4/17/2021 10:12 AM, Manfred wrote:
>> (cross-posting to comp.lang.c to let the heat fire up)
>>
>> On 4/17/2021 7:56 AM, Juha Nieminen wrote:
>>> I know that this is probably going to piss off avid C programmers,
>>> but I don't really care all that much.
>>
>> Excellent start
>>
>> [...]
>>>
>>> I myself happen to know both languages quite well, and in fact I
>>> program in both languages as my profession, and I would say that
>>> I am very knowledgeable and proficient in both languages and have
>>> no trouble in developing in either one. I am of the strong opinion
>>> that no, C is not a "simple" language, and that C++ makes so many
>>> things so much simpler, easier and safer.
>>>
>>> I was reminded of this in a quite concrete manner recently when I was
>>> trying to help a beginner programmer who had decided to try his hands
>>> on C, and wanted to create a simple text editor, which would read a
>>> text file, allow the user to edit the text in several ways, and to
>>> save the file.
>>>
>>> It quite quickly turned very frustrating for *both* of us ...
>>
>> The first comment that comes to mind is that probably part of the
>> frustration stems from your approach (no offense) to try and use in C
>> a design that would be suitable for C++ instead. Despite their name,
>> the two are quite different languages. The similarities are about
>> their runtime footprint, not about how they are used.
>>
>> For example, at a first glance the design of string object is not that
>> great for C.
>> A common pattern that pops to the mind is to use opaque structs (see
>> e.g. FILE*), and have something like:
>>
>> typedef struct string_t STRING;
>>
>> STRING* alloc_string(); // creates the empty string
>> STRING* set_string(STRING* s, const char* value);
>> void free_string(STRING* s);
>> STRING* concat_string(STRING* s1, STRING* s2);
>> ...
>>
>> This way there would be no ambiguity about how the STRING object has
>> to be used.
>> And yes, in C you have to do all yourself - C is a low level language,
>> and it is meant for low level stuff. It is hardly the right tool for
>> anything meant to interface with a human user - it is (still) great
>> for system programming and back-end processing, IMO.
>>
>> As second, I agree with Jacob that a text editor is a simple tool, but
>> it is not easy to make expecially for a beginner.
>>
>>
>> [snip]
>
> I would not call C easy. Instead, I would refer to it as being more to
> "the point", perhaps? Things have to be "explicit", it can be more
> verbose. I say that because C does not have RAII. Also, C is really nice
> to create plugins wrt creating portable bindings to other languages.
> Usually in C, things tend go like the following when coding up a new
> "object", so to speak:
>
> Typing in the newsreader, sorry for typos.
> ________________________________
>
> #include <stdio.h>
> #include <stdlib.h>
>
>
> struct foo
> {
>    int a;
>    void* mem;
> };
>
> int foo_create(struct foo* const self)
> {
>    if ((self->mem = malloc(sizeof(42))))
>    {
>        self->a = 84;
>        printf("foo_create(%p)\n", (void*)self);
>        return 1;
>    }
>
>    return 0;
> }
>
> void foo_destroy(struct foo const* const self)
> {
>    printf("foo_destroy(%p)\n", (void*)self);
>    free(self->mem);
> }
>
> void foo_output(struct foo const* self, FILE* output)
> {
>    printf("foo_output(%p)\n", (void*)self);
>    fprintf(output, "struct foo(%p)->a = %d\n", (void*)self, self->a);
>    fprintf(output, "struct foo(%p)->mem = %p\n", (void*)self, self->mem);
> }
>
>
> int main()
> {
>    struct foo foo;
>
>    if (foo_create(&foo))
>    {
>        foo_output(&foo, stdout);
>
>        foo_destroy(&foo);
>    }
>
>    return 0;
> }
> ________________________________
>
>
> See how I have to make an explicit call to foo_destroy? This can be
> handled in C++ in a "cleaner/safer" manner. Again, typing in the
> newsreader sorry for typos. This would be a simple C++ wrapper to the C
> API above:
> ________________________________
>
> struct foo_wrapper
> {
>    struct foo m_foo;
>
>    foo_wrapper() { if (! foo_create(&m_foo)) throw; }
>    ~foo_wrapper() { foo_destroy(&m_foo); }
>
>    void output(FILE* output_) const
>    {
>        foo_output(&m_foo, output_);
>    }
> };
>
> ________________________________
>
> Then we can go:
>
> {
>    foo_wrapper foo;
>    foo.output(stdout);
> }
>
> There. If it fails to create a foo in foo_create, it throws. Otherwise,
> foo_destroy is guaranteed to be called when foo goes out of scope. So,
> C++ can be more convenient, and safer. No need to use all of C++, but it
> does have its moments.

First learning about RAII, even when I learned about ScopeGuard, back in
my C++ days, for some reason, makes me think of the following song:

https://youtu.be/UZ2-FfXZlAU

Even though I was working with C/C++ well before this song was created,
it makes think way back when I was a little kid using basic on my Atari.

Juha Nieminen

unread,
Apr 22, 2021, 4:45:23 AM4/22/21
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> On Tue, 20 Apr 2021 04:02:30 +0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:
>> wij <wyn...@gmail.com> wrote:
>> > Once upon a time, C++ claimed being a superior system programming language.
>> > Luckily, Linus Torvalds was not fooled as most C++ beginners were.
>>
>> Almost nothing of what Linux wrote in that idiotic rant was true even back
>> when it was written, much less now.
>
> I would say it has about the same validity as your own arguments about C
> and how much easier C++ is for beginners

You are telling me in all seriousness that dynamic string manipulation in C
is as easy as it is in C++, and thus it makes no difference to a beginner
programmer which one he uses?

Seriously?

As for Linus's famous rant, I could write an entire book giving strong
arguments about why he was wrong even back when he wrote it, and how the
vast majority of the claims he presented in that rant were either completely
idiotic, irrelevant, or just outright false.

The only arguments I have seen from C programmers against my original post
have been "use this non-standard extension to make the language better
(not that C is bad and needs any extensions to make it better)".
Not a single actual refutation to my original point: Which one is simpler
from a beginner programmer's perspective, std::string in C++, or raw char
arrays in C (for which standard C offers pretty much no tools to make
their memory management easier or more automatic).

The irony here is that the C programmers making that argument are tacitly
admitting C to be limited and defective, and in bad need for extensions that
would make it better and easier to use. While still strongly maintaining
that it doesn't.

Oh, and of course the other type of argument: "Yeah? Well, how about
rvalue references!" As if that had anything at all to do about teaching
a beginner programmer about using dynamic strings. I find this "well,
C++ has its complexities too!" to be rather infantile because it doesn't
address the actual original argument.

> (you came up with a similar set of arguments about a year or so ago).

You are probably confusing me with someone else. I have not written about
this subject a year ago, or even two years ago.

Chris M. Thomasson

unread,
Apr 22, 2021, 4:48:55 AM4/22/21
to
On 4/22/2021 1:45 AM, Juha Nieminen wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>> On Tue, 20 Apr 2021 04:02:30 +0000 (UTC)
>> Juha Nieminen <nos...@thanks.invalid> wrote:
>>> wij <wyn...@gmail.com> wrote:
>>>> Once upon a time, C++ claimed being a superior system programming language.
>>>> Luckily, Linus Torvalds was not fooled as most C++ beginners were.
>>>
>>> Almost nothing of what Linux wrote in that idiotic rant was true even back
>>> when it was written, much less now.
>>
>> I would say it has about the same validity as your own arguments about C
>> and how much easier C++ is for beginners
>
> You are telling me in all seriousness that dynamic string manipulation in C
> is as easy as it is in C++, and thus it makes no difference to a beginner
> programmer which one he uses?

C++ is definitely easier... Perhaps, a nice lesson in C would be, how
could we get fairly close to std::string? So, lets get some simple
functions up and running. Concatenation, indexing into a string, ect...

Chris M. Thomasson

unread,
Apr 22, 2021, 4:51:21 AM4/22/21
to
On 4/22/2021 1:45 AM, Juha Nieminen wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>> On Tue, 20 Apr 2021 04:02:30 +0000 (UTC)
>> Juha Nieminen <nos...@thanks.invalid> wrote:
>>> wij <wyn...@gmail.com> wrote:
>>>> Once upon a time, C++ claimed being a superior system programming language.
>>>> Luckily, Linus Torvalds was not fooled as most C++ beginners were.
>>>
>>> Almost nothing of what Linux wrote in that idiotic rant was true even back
>>> when it was written, much less now.
>>
>> I would say it has about the same validity as your own arguments about C
>> and how much easier C++ is for beginners
>
> You are telling me in all seriousness that dynamic string manipulation in C
> is as easy as it is in C++, and thus it makes no difference to a beginner
> programmer which one he uses?
[...]

Perhaps start out with creating a dynamic array in C, then move on to
creating a deque using the dynamic array. Linking arrays together... All
of that fun stuff. ;^)

Juha Nieminen

unread,
Apr 22, 2021, 4:52:26 AM4/22/21
to
wij <wyn...@gmail.com> wrote:
> When thread was introduced in C++11, I needed to consider using it or not, too.
> But after weighing the gains and losses, I decided that RAII feature outweigh
> the efficiency. Thus, not using it.

That paragraph doesn't make much sense. Care to rephrase it?

(If you are claiming that RAII is inefficient, on what exactly do you base
that assumption?)

> C++ has several places violated its original OO principle, this is just one example.
> For instance, the added keyword override/final/delete (good, but it reflects the
> half-true "object model" crap) violated the C++ author's ideal (or guideline) about a
> a good language "...not add a new feature and then add another to disable it..."

What exactly is the problem with the 'override' keyword? It has zero effect on
object-oriented design in one direction or the other, and it helps avoiding
mistakes. So what's the problem?

As for 'delete', do you prefer the old method of declaring automatically
generated functions as private? That was a bit of a kludge in the first place,
which '=delete' fixes. Now you have a much clearer way to tell the compiler
to not autogenerate those functions, and to get better error messages.

MrSpook_l...@qdgb.org

unread,
Apr 22, 2021, 5:37:53 AM4/22/21
to
On Thu, 22 Apr 2021 08:45:08 +0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
>Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>Not a single actual refutation to my original point: Which one is simpler
>from a beginner programmer's perspective, std::string in C++, or raw char
>arrays in C (for which standard C offers pretty much no tools to make
>their memory management easier or more automatic).

Dynamic string handling in C really isn't that hard. You've got strdup()
and asprintf() to allocate and calling free() really isn't hard though
obviously you have to remember to do it! The only thing C really needs is
an appendString() function out the box but frankly writing one yourself is a 2
minute job.

But given the choice I'd use C++ and std::string.

MrSpook...@b3jtfv70fxckzmak.net

unread,
Apr 22, 2021, 5:41:09 AM4/22/21
to
On Thu, 22 Apr 2021 01:51:05 -0700
"Chris M. Thomasson" <chris.m.t...@gmail.com> wrote:
Back when I used to do C developer interviews one of my standard questions
would be "Write some code to create and use a linked list". The number of
people who didn't even know where to start never mind write working code
was quite worrying. I imagine they're the types now writing reams of
garbage javascript for websites.

Ben Bacarisse

unread,
Apr 22, 2021, 6:32:23 AM4/22/21
to
MrSpook_l...@qdgb.org writes:

> On Thu, 22 Apr 2021 08:45:08 +0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:
>>Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>>Not a single actual refutation to my original point: Which one is simpler
>>from a beginner programmer's perspective, std::string in C++, or raw char
>>arrays in C (for which standard C offers pretty much no tools to make
>>their memory management easier or more automatic).
>
> Dynamic string handling in C really isn't that hard. You've got strdup()
> and asprintf() to allocate

Not if you are referring to standard C. These are often available, but
the language itself, as standardised, does not have them.

> and calling free() really isn't hard though
> obviously you have to remember to do it!

Ensuring that free is called correctly often dictates the shape of a
function, which can be a distraction from writing the algorithm as
clearly as possible. Old C hands may do this semi-automatically, but
it's anther obstacle for beginners.

> The only thing C really needs is
> an appendString() function out the box but frankly writing one yourself is a 2
> minute job.

Without writing YASS (Yet Another String Struct), every append will
result in an allocation, a copy and a free. C programmers get used to
keeping the size around and over-allocating to ensure these costs are
ameliorated. None of it is hard, but it's more obstacles for beginners.

> But given the choice I'd use C++ and std::string.

ACK.

--
Ben.

MrSpook...@d6g.gov.uk

unread,
Apr 22, 2021, 6:38:20 AM4/22/21
to
On Thu, 22 Apr 2021 11:32:07 +0100
Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
>MrSpook_l...@qdgb.org writes:
>> Dynamic string handling in C really isn't that hard. You've got strdup()
>> and asprintf() to allocate
>
>Not if you are referring to standard C. These are often available, but
>the language itself, as standardised, does not have them.

If you only use the core language whether C or C++ you'll be rolling your
own for most things.

>> The only thing C really needs is
>> an appendString() function out the box but frankly writing one yourself is a
>2
>> minute job.
>
>Without writing YASS (Yet Another String Struct), every append will
>result in an allocation, a copy and a free. C programmers get used to
>keeping the size around and over-allocating to ensure these costs are
>ameliorated. None of it is hard, but it's more obstacles for beginners.

You can't get around the copy no matter how you manage the memory and
with an intelligent implementation of realloc() that attempts to extend the
current memory block hopefully the amount of free'ing will be limited too.


Ben Bacarisse

unread,
Apr 22, 2021, 7:35:23 AM4/22/21
to
MrSpook...@d6g.gov.uk writes:

> On Thu, 22 Apr 2021 11:32:07 +0100
> Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
>>MrSpook_l...@qdgb.org writes:
>>> Dynamic string handling in C really isn't that hard. You've got strdup()
>>> and asprintf() to allocate
>>
>>Not if you are referring to standard C. These are often available, but
>>the language itself, as standardised, does not have them.
>
> If you only use the core language whether C or C++ you'll be rolling your
> own for most things.

Sure. That's the focus of this particular criticism, I think.

Mind you, it also raises the question of why stop at strdup and
asprintf? A fuller string library would make it even easier!

>>> The only thing C really needs is
>>> an appendString() function out the box but frankly writing one yourself is a
>>2
>>> minute job.
>>
>>Without writing YASS (Yet Another String Struct), every append will
>>result in an allocation, a copy and a free. C programmers get used to
>>keeping the size around and over-allocating to ensure these costs are
>>ameliorated. None of it is hard, but it's more obstacles for beginners.
>
> You can't get around the copy no matter how you manage the memory and
> with an intelligent implementation of realloc() that attempts to extend the
> current memory block hopefully the amount of free'ing will be limited
> too.

I don't think I was clear. If a string is represented as nothing more
that a pointer, appendString() will be expensive. You have to choose
between a simple interface or more efficient allocation. With

char *appendString(const char *s1, size_t len, const char *s2)

you can avoid a strlen call but if realloc is to be used the beginner
must know the rules: that the string being appended to must be allocated
and not be static, and that the contents of it will change.

And to guarantee efficient string growth, you need appendString to over
allocate and return the size_available as well.

--
Ben.

Chris Vine

unread,
Apr 22, 2021, 8:35:19 AM4/22/21
to
On Thu, 22 Apr 2021 08:45:08 +0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> > On Tue, 20 Apr 2021 04:02:30 +0000 (UTC)
> > Juha Nieminen <nos...@thanks.invalid> wrote:
> >> wij <wyn...@gmail.com> wrote:
> >> > Once upon a time, C++ claimed being a superior system programming language.
> >> > Luckily, Linus Torvalds was not fooled as most C++ beginners were.
> >>
> >> Almost nothing of what Linux wrote in that idiotic rant was true even back
> >> when it was written, much less now.
> >
> > I would say it has about the same validity as your own arguments about C
> > and how much easier C++ is for beginners
>
> You are telling me in all seriousness that dynamic string manipulation in C
> is as easy as it is in C++, and thus it makes no difference to a beginner
> programmer which one he uses?
[snip]

I wasn't commenting specifically on string manipulation, which is
something C++ does better. I was commenting on your more general point
that C++ is considerably easier for beginners to learn.

On the specific point of string manipulation, a beginning wanting to
become a competent C++ programmer is going to have to learn the
principles of how C strings work fairly early on, because similar issues
are applicable to other resource management cases for which C++ does
not provide a standard library wrapper, and for which programmers are
going to have to write their own wrapper classes. And of course
std::string does expose C strings in its interface. You are simply not
going to get very far in C++ if you don't understand C strings.

> > (you came up with a similar set of arguments about a year or so ago).
>
> You are probably confusing me with someone else. I have not written
> about this subject a year ago, or even two years ago.

I think I was thinking of your contributions to the thread "Why should
a c programmer learn c++", in which as I recall you made similar
points. But I am willing to be corrected.

Manfred

unread,
Apr 22, 2021, 10:31:11 AM4/22/21
to
On 4/22/2021 10:45 AM, Juha Nieminen wrote:
> The only arguments I have seen from C programmers against my original post
> have been "use this non-standard extension to make the language better
> (not that C is bad and needs any extensions to make it better)".
> Not a single actual refutation to my original point: Which one is simpler
> from a beginner programmer's perspective, std::string in C++, or raw char
> arrays in C (for which standard C offers pretty much no tools to make
> their memory management easier or more automatic).

For what is worth, my argument is somewhat different:

If you try to use a design that would be well suited for C++, it is no
surprise that the same design will lead to frustration if attempted with
in C. Again, despite their name, the languages are very different.

In addition, there are well known ways to do OO programming in C, but
from the examples you described your attempt was to replicate in C some
C++ code style instead, with all the clumsiness that may be expected
from such approach.

C and C++ have both their strong suits (I am not talking about
performance only) - the fact that string manipulation has a much more
comprehensive support in C++ does not make C++ a better language in
absolute terms, the same applies to containers, the standard library and
all the bells and whistles of C++ - all of these are useful features,
but they are only relevant if actually essential to the problem domain,
otherwise they constitute extra baggage that is best not paid for.

One field where C++ really stands up, IMO, is templates and generic
programming - here the life of a C programmer would get really
miserable, but again, it is only as useful as what you are building
actually needs it.

(for the record, I have have been using C++ much more than C in my
career, and almost exclusively C++ in more recent years - this is to say
that I am probably not the most keen of C fans)

>
> The irony here is that the C programmers making that argument are tacitly
> admitting C to be limited and defective, and in bad need for extensions that
> would make it better and easier to use. While still strongly maintaining
> that it doesn't.

It is true that the feature portfolio of C++ is considerably larger than
that of C. As far as I am concerned, this is only a benefit if your
problem domain needs such extra features, otherwise it is actually a
drawback.

https://www.stroustrup.com/P0977-remember-the-vasa.pdf

wij

unread,
Apr 22, 2021, 12:26:14 PM4/22/21
to
Checked again from https://en.cppreference.com/w/cpp/thread/thread, along with
my document and email. Woo, I could have read a premature version of
std::thread (I do not use C++ standard library). I have been so wrong for these years.
Sorry about this part.

wij

unread,
Apr 22, 2021, 12:41:47 PM4/22/21
to
On Thursday, 22 April 2021 at 16:52:26 UTC+8, Juha Nieminen wrote:
> wij <wyn...@gmail.com> wrote:
> > When thread was introduced in C++11, I needed to consider using it or not, too.
> > But after weighing the gains and losses, I decided that RAII feature outweigh
> > the efficiency. Thus, not using it.
> That paragraph doesn't make much sense. Care to rephrase it?
>
> (If you are claiming that RAII is inefficient, on what exactly do you base
> that assumption?)

Checked again from https://en.cppreference.com/w/cpp/thread/thread, along with
my document and email. Woo, I could have read a premature version of
std::thread (I do not use C++ standard library). I have been so wrong for these years.
Sorry about this part.

> > C++ has several places violated its original OO principle, this is just one example.
> > For instance, the added keyword override/final/delete (good, but it reflects the
> > half-true "object model" crap) violated the C++ author's ideal (or guideline) about a
> > a good language "...not add a new feature and then add another to disable it..."
> What exactly is the problem with the 'override' keyword? It has zero effect on
> object-oriented design in one direction or the other, and it helps avoiding
> mistakes. So what's the problem?
>
> As for 'delete', do you prefer the old method of declaring automatically
> generated functions as private? That was a bit of a kludge in the first place,
> which '=delete' fixes. Now you have a much clearer way to tell the compiler
> to not autogenerate those functions, and to get better error messages.

As you can only focus on partial sight, like the cases of string manipulations in C.
I cannot make it more clear for you.

wij

unread,
Apr 22, 2021, 1:14:23 PM4/22/21
to
I built a dual(mix) mode DOS environment in probably 1999, a last struggle
to sustain software life. So my question is where "placement new" was from?

Chris M. Thomasson

unread,
Apr 22, 2021, 3:38:53 PM4/22/21
to
Oh God! Well, here is some of my crude JavaScript in action:

http://funwithfractals.atspace.cc/ct_fdla_anime_dynamic_test

And, yes it uses a linked list... ;^)

Juha Nieminen

unread,
Apr 23, 2021, 3:12:40 AM4/23/21
to
MrSpook...@b3jtfv70fxckzmak.net wrote:
> Back when I used to do C developer interviews one of my standard questions
> would be "Write some code to create and use a linked list". The number of
> people who didn't even know where to start never mind write working code
> was quite worrying.

Did you score highly if anybody would start explaining the difficulty of
creating a generic linked list in C, and asking all kinds of questions
on what exactly the requirements are for the implementation?

I would immediately ask "a linked list containing what kind of nodes?"
Should it be a generic type of linked list where the calling code gets
to decide what the elements contain? Or should it be just a "hard-coded"
linked list where the content is predetermined, for one particular specific
use? If it should be generic, how should the programmer be able to specify
the contents of the nodes? Should the linked list code support constructing
and destructing the nodes with user-provided construction and destruction
functions?

It would be the perfect example of how such a task would be so much easier
in C++, as the language directly provides the mechanisms for the programmer
to specify the node type, and for those nodes to be automatically
constructed and destroyed properly, without the linked list code having
to worry about it or change its interface according to such requirements.

Honestly, if I were in a situation where I'm programming in C (yes, I have
to do that too), and a linked list would seem to be like the best
solution to a particular problem, I would at a very minimum think a bit
about whether there would be an easier and better solution, rather than
deal with the nightmare of memory management of a linked list (with nodes
that might themselves require memory management).

Juha Nieminen

unread,
Apr 23, 2021, 3:20:51 AM4/23/21
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> You are simply not
> going to get very far in C++ if you don't understand C strings.

The problem in this case is not understanding how C strings work, but
managing dynamically allocated (and length-changing) strings.

> I think I was thinking of your contributions to the thread "Why should
> a c programmer learn c++", in which as I recall you made similar
> points. But I am willing to be corrected.

My arguments there were essentially "you aren't really losing anything
by moving to C++ from C (in terms of features and efficiency)".

Juha Nieminen

unread,
Apr 23, 2021, 3:32:40 AM4/23/21
to
Manfred <non...@add.invalid> wrote:
> If you try to use a design that would be well suited for C++, it is no
> surprise that the same design will lead to frustration if attempted with
> in C. Again, despite their name, the languages are very different.

The attempt to modularize, abstract away, the dynamic memory management of
strings is much better than trying to manage all that mess directly in the
code that's using those strings, by using just raw char pointers and trying
to always do the right thing in-line (such as reallocating, copying,
appending, shrinking, freeing...). It only makes sense to create helper
functions for all the needed string operations, and for those functions to
operate on a struct that contains any necessary data to manage the string
(such as its current length and its allocated capacity).

I can't think of a better way that makes the code simpler and easier.

This is *not* a case of "trying to do C++ in C". This is a case of trying
to use *modular design* in C. To use abstractions that make it much easier
and safer to manage dynamically allocated length-changing strings.

> C and C++ have both their strong suits (I am not talking about
> performance only) - the fact that string manipulation has a much more
> comprehensive support in C++ does not make C++ a better language in
> absolute terms, the same applies to containers, the standard library and
> all the bells and whistles of C++ - all of these are useful features,
> but they are only relevant if actually essential to the problem domain,
> otherwise they constitute extra baggage that is best not paid for.

I can't think of many situations where C shines over C++.

Perhaps some kind of minor argument could be presented about C having
the 'resrtict' keyword, which C++ lacks. Or about VLAs. But I'm not
sure those would be reason enough to choose C over C++ regardless of
the task at hand.

I program in both C++ and C as my job. C is usually chosen when there
are no other options (such as when programming for certain 8-bit
embedded processors). Quite often (and fortunately) when C is the only
viable opion, the hardware is so limited that dynamic memory allocation
is usually out of the question, so the C code is restricted to fully
static memory management, which is largely non-problematic and quite
straightforward. (In those 8-bit processors you usually don't even need
any dynamic memory allocation at any point.)

C is ok of a language to program with in such restricted situations.

Juha Nieminen

unread,
Apr 23, 2021, 3:34:26 AM4/23/21
to
wij <wyn...@gmail.com> wrote:
>> > C++ has several places violated its original OO principle, this is just one example.
>> > For instance, the added keyword override/final/delete (good, but it reflects the
>> > half-true "object model" crap) violated the C++ author's ideal (or guideline) about a
>> > a good language "...not add a new feature and then add another to disable it..."
>> What exactly is the problem with the 'override' keyword? It has zero effect on
>> object-oriented design in one direction or the other, and it helps avoiding
>> mistakes. So what's the problem?
>>
>> As for 'delete', do you prefer the old method of declaring automatically
>> generated functions as private? That was a bit of a kludge in the first place,
>> which '=delete' fixes. Now you have a much clearer way to tell the compiler
>> to not autogenerate those functions, and to get better error messages.
>
> As you can only focus on partial sight, like the cases of string manipulations in C.
> I cannot make it more clear for you.

Because I complain about dynamic string manipulation in C, you can't explain
why you oppose C++ keywords like 'override' and 'delete'?

MrSpook...@66h4_0ccefudc0u8w.gov

unread,
Apr 23, 2021, 5:15:04 AM4/23/21
to
On Fri, 23 Apr 2021 07:12:30 +0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
>MrSpook...@b3jtfv70fxckzmak.net wrote:
>> Back when I used to do C developer interviews one of my standard questions
>> would be "Write some code to create and use a linked list". The number of
>> people who didn't even know where to start never mind write working code
>> was quite worrying.
>
>Did you score highly if anybody would start explaining the difficulty of
>creating a generic linked list in C, and asking all kinds of questions
>on what exactly the requirements are for the implementation?

Back in those days you have enough time to get them to solve a few algorithmic
issues and ask a few pertinent questions then its on to the "Tell me about
yourself HR waffle". These days employers seem to think they need to give
potential employees a cut down CS degree exam, sometimes done over seperate
days. IMO if you can't tell someones coding ability in 30 mins then you
shouldn't be an interviewer.

>It would be the perfect example of how such a task would be so much easier
>in C++, as the language directly provides the mechanisms for the programmer
>to specify the node type, and for those nodes to be automatically
>constructed and destroyed properly, without the linked list code having
>to worry about it or change its interface according to such requirements.

Or you could just use std::list. The point was to show that they understood
basic data structures and memory allocation.

>to do that too), and a linked list would seem to be like the best
>solution to a particular problem, I would at a very minimum think a bit
>about whether there would be an easier and better solution, rather than
>deal with the nightmare of memory management of a linked list (with nodes
>that might themselves require memory management).

If you need a linked list you need a linked list. Using an array or hash
would be the wrong answer.

Chris Vine

unread,
Apr 23, 2021, 6:02:12 AM4/23/21
to
On Fri, 23 Apr 2021 07:20:39 +0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> > You are simply not
> > going to get very far in C++ if you don't understand C strings.
>
> The problem in this case is not understanding how C strings work, but
> managing dynamically allocated (and length-changing) strings.

That as well then.

First, if beginners are to write their own RAII classes effectively,
they need to know how dynamically allocated memory works; and secondly
beginners cannot I believe call themselves even moderately competent
until they understand RAII, as it is so fundamental in C++.

I would go further and say that a beginner cannot properly understand
the use of std::unique_ptr and std::shared_ptr without understanding
both dynamically allocated memory and RAII. Also, I do not believe
that either dynamically allocated memory or RAII are difficult
concepts for a beginner to understand, once object lifetime is grasped.

jacobnavia

unread,
Apr 23, 2021, 6:10:51 AM4/23/21
to
Le 20/04/2021 à 23:07, Chris M. Thomasson a écrit :

>
> For some reason, anytime I hear somebody go, just use a GC... Well, it
> makes think of this song:
>
> https://youtu.be/WJabPYimznY
>
> Or the following scene in Disney's Dragonslayer from 1981:
>
> https://youtu.be/TJRaLnLDMWg

Great arguments!

Technically sound, I am convinced now...


... that you have nothing to say

wij

unread,
Apr 23, 2021, 7:10:37 AM4/23/21
to
Let it burn. I like to play fire, safely.

This is not the exact one in my memory, but close.
https://www.youtube.com/watch?v=ajNieXqs8XE

wij

unread,
Apr 23, 2021, 7:59:01 AM4/23/21
to
I did not oppose 'override','delete' (I like it, instead). The main point is the
language design principle or ideal avoiding "invent a new feature and then
another one to disable it...". In this case I refer to C++ inheritage ideal
("object model" crap.). This principle can extend further to be not so rightful,
as many ideals are.

std::string provides "helper functions" to manipulate "C-string"
(precisely speaking, this was an error of 'pure' C++, we are now actually
talking about an erroneous feature of C++), does not mean C is ugly.

Helper functions(or macro/template) come with cost (user usually do not care,
but note that it can accumulate) and can not cover all cases. You cannot use
memcpy/memmove in 'pure' C++.

As to the memory allocation issue, in extreme cases (real programs will encounter),
e.g. many string objects, or one long string, one might even need to use zero-terminate
c-string directly and RAII becomes a hinder.

Paavo Helde

unread,
Apr 23, 2021, 8:44:52 AM4/23/21
to
This is all fine and good, but missing a point that this is all not
needed for beginners for just using some strings. In C++ a string is
effectively a simple scalar value object as it should be, there are no
issues with dynamic allocation, lifetime or RAII.

Yes, the *implementation* of strings does use all of this, but this has
no relevance for beginners. There are tons of other things in C++ to
learn, the implementation of strings can be well postponed. It has
absolutely no importance to a beginner that a string is technically
stored as an array of bytes somewhere.





Chris Vine

unread,
Apr 23, 2021, 12:52:19 PM4/23/21
to
Sure, but that was not my point. In the thread to which I was
replying, a beginner's struggles with string manipulation was used as a
proxy for the argument that C, although much smaller as a language than
C++, is not simpler than C++ and that C++ is easier to learn.

My view is that that is an unhelpful proxy: C++ may postpone the day
when the beginner has to expand her knowledge to include issues such as
the resource management which caused the beginner's misunderstandings
with string manipulation in C, but not by much. In my view, as I said,
"both languages are difficult for beginners and require a high degree
of skill to use well".

To digress, I will certainly agree that C++'s ubiquitous use of RAII
reduces the mistake count as compared with the equivalent code in C,
but I don't think that that was the point being made.

Manfred

unread,
Apr 23, 2021, 2:36:13 PM4/23/21
to
On 4/23/2021 9:32 AM, Juha Nieminen wrote:
> Manfred <non...@add.invalid> wrote:
>> If you try to use a design that would be well suited for C++, it is no
>> surprise that the same design will lead to frustration if attempted with
>> in C. Again, despite their name, the languages are very different.
>
> The attempt to modularize, abstract away, the dynamic memory management of
> strings is much better than trying to manage all that mess directly in the
> code that's using those strings, by using just raw char pointers and trying
> to always do the right thing in-line (such as reallocating, copying,
> appending, shrinking, freeing...). It only makes sense to create helper
> functions for all the needed string operations, and for those functions to
> operate on a struct that contains any necessary data to manage the string
> (such as its current length and its allocated capacity).
>
> I can't think of a better way that makes the code simpler and easier.

These are design goals that make sense in many domains.
My point is that they /can/ be used in C as well, although, granted,
considerably more verbosely than in C++.

However, the way to do this in C is not how it looks you were trying to
do it from the sketches you presented:

> String str1 = String_with_cstr("hello");
> String str2 = str1;

>
> This is *not* a case of "trying to do C++ in C".
I think it is. We may agree to disagree - just my view of it.

This is a case of trying
> to use *modular design* in C. To use abstractions that make it much easier
> and safer to manage dynamically allocated length-changing strings.
And I don't think the proper way to use modular design in C is how you
sketched it. Again, just my perspective.

>
>> C and C++ have both their strong suits (I am not talking about
>> performance only) - the fact that string manipulation has a much more
>> comprehensive support in C++ does not make C++ a better language in
>> absolute terms, the same applies to containers, the standard library and
>> all the bells and whistles of C++ - all of these are useful features,
>> but they are only relevant if actually essential to the problem domain,
>> otherwise they constitute extra baggage that is best not paid for.
>
> I can't think of many situations where C shines over C++.

- Stability
- Portability
- Interoperability
- Availability

As I said earlier, I put performance aside because it is often
overestimated, and most of the times C and C++ are on par. Smaller
runtime footprint is maybe the most common plus of C in this respect.

>
> Perhaps some kind of minor argument could be presented about C having
> the 'resrtict' keyword, which C++ lacks. Or about VLAs. But I'm not
> sure those would be reason enough to choose C over C++ regardless of
> the task at hand.

If you look at the language syntax and semantics, then strictly speaking
for the most part C is a subset of C++. (although what of C++ is outside
C is so huge that the way the two languages are meant to be used is
substantially different)

The comparison would be about how much value is added by the extra
features of C++ (which is a huge amount) compared to the cost of
handling them (learn/design/maintain). Obviously this is heavily
dependent on the problem domain.

>
> I program in both C++ and C as my job. C is usually chosen when there
> are no other options (such as when programming for certain 8-bit
> embedded processors). Quite often (and fortunately) when C is the only
> viable opion, the hardware is so limited that dynamic memory allocation
> is usually out of the question, so the C code is restricted to fully
> static memory management, which is largely non-problematic and quite
> straightforward. (In those 8-bit processors you usually don't even need
> any dynamic memory allocation at any point.)
>
> C is ok of a language to program with in such restricted situations.
>

I have seen successful large projects in C, mostly back end services.
It is loading more messages.
0 new messages