C vs. C++

J

jacob navia

Kaz said:
Because, remember, kids, C++ references are not pointers and
are a lot safer!

:)

Yes, and that is why I added references to my C compiler implementation.
This will make everyone angry of course. Both C++ AND C fans

:)

flames /dev/null
 
J

James Kuyper

REH said:
I know what he was looking for, but you can't argue elegance, and then
restrict what language features I am allowed to use.

It's not a matter of which language features you're allowed to use; it's
a matter of reading the specifications. The specification was "One
single malloc() call", and your code doesn't meet that specification.
Would it make the specification any clearer if I replaced "malloc()"
with "my_func()", a function with a similar interface, for which no
simple C++ feature was an exact match?
> ... Either way, you
are wrong. The language DOES allow me to guarantee that new calls
malloc, if I want it to.

Sure, it does; that adds a lot more than 6 extra characters.
... Pedantic: You are also wrong I need a cast to
use malloc in C++. You can do it without a cast, but would require
more than 6 extra characters.

Same point.
 
R

REH

err... how do you do that? Define your own operator new?


I bet it isn't simple either...

Actually, it's very simple, but again, would require more (about 2X)
characters than a cast.

REH
 
P

Phil Carmody

Ian Collins said:
Try implementing RAII directly in C.

That's a meaningless response. Why not go the whole hog and just
say "Try implementing the whole program as a single regexp"?
Believe you me, Perl golfers do that daily.

Phil
 
P

Phil Carmody

Ben Bacarisse said:
Absolutely, but the question then deteriorates to a rather trivial
feature list.

What do you mean by "then"? You seem to have overlooked the
"already"!

Phil
 
I

Ian Collins

Phil said:
That's a meaningless response.

No it isn't. I challenge anyone to implement a general solution to RAII
in C.

My three most compelling reasons (in order) for using C++ for driver
code are RAII, code reuse through inheritance and operator overloading
(especially where hardware is accessed through get/set functions).

The latter two are a convenience; RAII is a real benefit.
 
I

Ian Collins

Malcolm said:
It means that C++ allows for a possibility of bad programming that C
excludes. Since most softwware projects that fail do so because the
human programmers cannot manage the complexity of what they have
created, this is quite a serious drawback.
Allowing code complexity beyond programmer comprehension is a process
bug, not a language one.
 
J

John Bode

It means that C++ allows for a possibility of bad programming that C
excludes. Since most softwware projects that fail do so because the human
programmers cannot manage the complexity of what they have created, this is
quite a serious drawback.

C and C++ give you roughly the same amount of rope with which to hang
yourself. C++ just allows you to tie fancier knots.

Again, it does not follow that C's relative simplicity makes it
inherently superior to C++ for any and all tasks. Templates have, for
me, made certain tasks go a lot faster by reducing the amount and,
yes, *complexity* of the code I would have had to write were I using
C. Text processing is a lot less painful in C++. There are times
when the tradeoffs are simply not worth it, and C is the better
solution. But it's not *universally* true.
 
R

Richard

John Bode said:
C and C++ give you roughly the same amount of rope with which to hang
yourself. C++ just allows you to tie fancier knots.

Again, it does not follow that C's relative simplicity makes it
inherently superior to C++ for any and all tasks. Templates have, for
me, made certain tasks go a lot faster by reducing the amount and,
yes, *complexity* of the code I would have had to write were I using
C. Text processing is a lot less painful in C++. There are times
when the tradeoffs are simply not worth it, and C is the better
solution. But it's not *universally* true.

And once more, which C program can you write that you can not almost
identically in C++?
 
S

s0suk3

Tomás Ó hÉilidhe said:
    There is /nothing/ that can be achieved more elegantly or more
efficiently in C, than it can be achieved in C++. Nothing. If you
think there's something then I'll listen intently.

The following is valid in C but not in C++:
        char data[8] = "abcdefgh";

If you change the array size to 9 bytes, then it is valid in C
and in C++, but wastes 1 byte.  Therefore, it is more efficient
to define such an array in C than in C++.  One could use an
alternate form of initializer, e.g. {'a', 'b', 'c', 'd', 'e',
'f', 'g', 'h'}, in C++, but that's less elegant than using a
string literal.

That seems like a hack to me (then again, you're "just another C
hacker" :), because the array is not a "string" anymore, even though
you've initialized it with a string literal, which is misleading.

If you want a set of values rather than a string, then do provide a
brace-enclosed set of values rather than a string literal:

// I want these character values
char data[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'};

// I want a string
char data[] = "abcdefgh";

Sebastian
 
R

REH

... snip ...


... snip ...



I am ignorant about C++.  But, from what little I know, it seems to
me that the cast is essential.  How am I wrong?

This isn't normally done because the cast is simpler. But C++ allows
you to give it the memory you wish to construct an object at (called
placement new). Thus, the long way around would be:

int* p = new(malloc(sizeof(int))) int(123);

which is equivalent to:

int* p = (int*) malloc(sizeof(int));
*p = 123;

although, the more acceptable C++ way of casting in this case would
be:

int*p = static_cast<int*>(malloc(sizeof(int)));

which is considered inferior to:

int* p = new int;

REH
 
K

Kaz Kylheku

It means that C++ allows for a possibility of bad programming that C
excludes. Since most softwware projects that fail do so because the human
programmers cannot manage the complexity of what they have created, this is
quite a serious drawback.

If this is the case, the complexity leading to the failure is in the /project/,
not in the /programming language/.

Complexity has to exist somewhere. If you banish it from the programming
language, you push it into the programs. It's not an exact conservation law,
because a given amount of complexity in one place may translate into vastly
more complexity if it is relocated to another place, due to duplication of
effort.

C++ can manage certain complexities that are otherwise difficult in C.

As a rule:

language simplicity => program complexity

It helps to look at backwards. If you have large body of code written in a
complex programming language, and you want to simplify the programming
language, as a rule that will require adding reams of code to that existing
code to compensate. Every little thing you remove from the language will
potentially have an impact over broad areas of the existing code base,
potentially requiring reams of complexity to be heaped onto it.

Whatever /single/ thing you don't have in a language for taking care of some
responsibility translates to countless repetition of that responsibility.
This is particularly true of language features that generate code. It's less
true of library features. If you take a function out of a library, you might be
able to just add that function to your program. You might have a big library
used by everyone in your your software organization, so you might be able to
just add it in one place even for many programs. But there are still other
organizations that will be similarly reinventing the function.

You might not like C++ templates, but what would have to be done to a C++
codebase that is based on templates, if templates were taken away, and how does
that task compare to the complexity of templates? What if the codebase is much
larger and more complex than the implementation of templates?
 
K

Kaz Kylheku

That's a meaningless response.

It's a competely meaningful response, because RAII is a piece of complexity in
the C++ programming language which evacuates a whole ton of repeated complexity
from programs written in the C++ language.

Everything that RAII /does/ can be written as explicit function calls, any of
which can be easily forgotten by the programmers.

Not only that, but because RAII provides automatic destruction when terminating
a statement block by any path, your C code also has that responsibility to
replicate. That's the other half: deinitialization is resource release, or
DIRR?

There is value in having all that generated for you. Code that writes code is
not always mere syntactic sugar. Syntactic sugar is when you have some trivial
shorthand that lets you use one kind of syntax to represent another, without
any deep semantics being attached.

Not all programming language features are syntactic sugar. For instance control
structures like while loops are not mere syntactic sugar for if/goto.
Parameter passing and value returning is not merely syntactic sugar for pushing
registers onto a stack.

Syntactic sugar is not without value, but "semantic sugar" is even more
valuable.
Why not go the whole hog and just
say "Try implementing the whole program as a single regexp"?
Believe you me, Perl golfers do that daily.

Perl golfers can do in a day what would take you weeks of coding in C, at the
culmination of which you'd cave in and complete the project by linking in
the perl-compatible regular expression library.
 
K

Kaz Kylheku

Look Richard, C++ is just syntactic sugar around C.

Proof:

Comeau C++ compiler works by generating C, not assembly.

Comeau C++ compiler works by generating C much faster and more reliably
than a C programmer could write it.

A single change to the C++ program can result in changes all over the generated
C code, which no C programmer, or even a whole team, could accomplish in the
same amount of time, and with the same level of completeness (not missing any
place where the change needs to be applied) and correctness (not screwing up
any of the applied changeds).

A change to the parameters used to invoke the Comeau C++ compiler can
also reshape all of that C code, whereas no such parametrized control mechanism
exists for reshaping hand-maintained C code.

If a bug is found in the way that C code is generated by Comeau C++, the
compiler can be fixed and re-run to regenerate the code and fix all instances
of that problem in the C code.

No C programmer could find all recurrences of some systematic bug in a large C
code base in the same amount of time, with the same level of completeness and
reliability as an automatic recompile.

The C code generated by the Comeau C++ compiler is usually trusted to the
degree that few bother reading the output; they work with the program in terms
of the C++ representation. Would you trust hand-written C without examining
it?

See, there are rational considerations that prevent the reasonable man from
concluing that every Turning complete language is just syntactic sugar for any
other just because you can compile one to the other.

Not all translation is mere syntactic manipulation. Syntactic sugar is when you
have some trivial syntax-to-syntax transformation that doesn't really change
what you are expressing, but only gives you a notational change.
 
C

CBFalconer

REH said:
This isn't normally done because the cast is simpler. But C++
allows you to give it the memory you wish to construct an object
at (called placement new). Thus, the long way around would be:

int* p = new(malloc(sizeof(int))) int(123);

which is equivalent to:

int* p = (int*) malloc(sizeof(int));
*p = 123;

although, the more acceptable C++ way of casting in this case
would be:

int*p = static_cast<int*>(malloc(sizeof(int)));

which is considered inferior to:

int* p = new int;

Ugh. Just the fact that such a thing is allowed puts me off C++.
 
D

Dik T. Winter

>
> What do you mean by "then"? You seem to have overlooked the
> "already"!

Indeed, the featurelist is not even interesting. You can program complete
arithmetic in a language that only supports the Peano axioms. If you can
write functions (or operators) in that language you get complete arithmetic,
possibly a but more cumbersome (when operators can not be defined) or just
trivial. The speed will be a bit different, but that was not the question.

Consider a C-like language, where the only arithmetic primitive is the
successor function on intger, and with the ability to define operators.

Consider for unsigned numbers the following operator and function definition:
unsigned int pred(unsigned int i) {
unsigned int k, k1 = 0;
k = succ(k1);
if(i == 0) error("underflow");
while(k < i) {
k1 = k; k = succ(k);
}
return k1;
}
unsigned int "+"(unsigned int i, unsigned int j) {
while(j > 0) {
i = succ(i); j = pred(i);
}
return i;
}
Functionally there is no difference between 2+5 in that language and in
C. (But C is a bit faster. And note that I did not yet consider wraparound
above, but that is easily fixed.)
 
R

Richard

CBFalconer said:
Ugh. Just the fact that such a thing is allowed puts me off C++.

I would be interested to hear which part puts you off as it could be one
of many things.

And I'm totally confused as to where this "cast is essential" is
from. Since you generally use new from what I can remember and that
returns the reference to the correct type/class.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top