tags:

views:

1138

answers:

13

What are the things that can be done in C but not in C++, and which of these features do you miss the most while coding in C++?

Few things I can think of:

  1. We can assign any type of pointer to void pointer without cast in c but not in c++.
  2. Declare variable names that are keywords in C++ but not C ;)

EDIT : Thanks @sbi for pointing out:
1. should be: We can assign void pointer to any type of pointer in C but not in C++

+2  A: 

You can have variable-length array in C but not in C++. I believe this will be quite useful instead of doing a new[] for this.

Naveen
But then C++ has `std::vector<>`.
sbi
@sbi: vector is nasty.
Matt Joiner
@sbi: Nice one, Since vectors are inherent part of C++ standard, we cant say feature missing, just that implemented under different name.
Als
available only in C99
Vijay Mathew
`vector` allocates memory on heap, VLA may allocate memory on stack. Since most of the times heap allocation is costlier than stack allocation, I believe this will be useful.
Naveen
Interesting. Never used this. It's easily emulated with malloc/free or new/delete though.
Matt H
@Naveen: Indeed, this is an important difference. While you could, in theory, use a stack allocator with `std::vector` there's non out of the box and writing allocators is not exactly a beginner's task.
sbi
@Matt: That's one of those comments that makes you wish for comment down-voting. You're accusing it without any rationale. What am I to do with this but disregard it?
sbi
@sbi: Vector forces you to consider vectors as a replacement for arrays. But vectors are a limited implementation of arrays: They imply heap allocation, resizing, and special treatment of non-PODs. In addition there is additional mental and performance overhead.
Matt Joiner
@Matt: I'm not sure how vector forces anything on you. And if you don't need resizing, there's `std::array` for you. Also, I have no idea in what respect `std::vector` treats non-PODs differently from PODs (except that some implementation might optimize based on the distinction). Having taught C++ for years, I can testify that beginners seem to find `std::vector` far easier to grok than C arrays. And, finally, I have yet to see measurements showing `std::vector` being slower than C arrays.
sbi
@Matt Joiner: "vectors are a limited implementation of arrays:" No. Vectors are objects which can mimick arrays, and have additional features. As for performance issue, the last time I profiled code, `strlen` was the guilty party, not the C++ vector or string.
paercebal
@Matt: 1) I don't see any requirement for vector using dynamically allocated memory (stack). 2) I see no guarantee that VLA are implemented on the heap. 3) Vectors are not limited arrays, in-fact they have more functionality (and can be converted into arrays (pointers) at no cost) 4) There is no speed difference between vectors and arrays in usage. 5) Since vector implements the same interface that an array provides there is no **mental** performance overhead.
Martin York
There's nothing to stop you writing a vector-like class that allocates its storage on stack. std::vector itself can't do so because it's supposed to be resizeable, but another class could.I suspect that the fact that the standard library does not include such a class indicates that nobody on the committee thought that it would be useful.
dajames
Actually I don't think it is possible to create a vector-like class on the stack at all. Everything about classes requires that you enter a new stack-frame to execute their methods. Resizability is a given, this is obviously not possible. stuff like scoped_array is reasonable, but heap based.
Matt Joiner
@Matt Joiner: It's possible to create a vector-like class on the stack. Just use the "alloca" function for allocation. The only drawback would be the comment in the description of this class: "Only declare this variable on the stack", which is the same limitation suffered by the VLA.
paercebal
@paercebal: One of us has missed something. Upon returning from the "stack-vector" method invoking alloca, the contents would be lost.
Matt Joiner
@Matt Joiner: You're right. For my class "MyVLA", the `alloca()` call is made by a macro, not the constructor. But this code remains C++ code (as BOOST_FOREACH is a macro, and remains C++ code anyway). See my second answer at http://stackoverflow.com/questions/3879636/what-can-be-done-in-c-but-not-c/3901262#3901262
paercebal
+4  A: 
  1. We can assign any type of pointer to void pointer without cast in c but not in c++.

Any pointer is convertible to a void* in C++ as well. You're losing information that way and the compiler won't stop you from doing that. It's the opposite that's a problem, because that way you're gaining information that the compiler can't check.

I think C allows this, while C++ definitely does not.

sbi
@sbi point taken.Thanks!
Als
I'd like to know why this was down-voted. What's wrong with it?
sbi
+2  A: 

In C, you can implicitly convert between void pointers and other pointers, but you must do an explicit conversion in C++.

void* a;
int* b;

a = b;  // Invalid in C++, but not in C
b = a;  // Valid in C and C++
a = (void*)b; // Valid in C and C++
b = (int*)a;  // Valid in C and C++
Alexander Rafferty
a = b is legal.
PigBen
Is it? I'll have to double-check.
Alexander Rafferty
Moreover b = a is illegal in C++.
Adam Bowen
+17  A: 

You might find the webpage Incompatibilities Between ISO C and ISO C++ interesting.

I mostly miss a number of C99 features that are not in C++:

  • Compound literals;
  • Designated initializers;
  • Variable argument macros (included in C++0X).
schot
Best answer so far. I never missed those things, but I can see how someone could like them.
Amigable Clark Kant
Variable argument macros, isn't that what templates are for? Horrific things I know but...
Amigable Clark Kant
@schot: Thanks for the link! too bad the internet filters at work wont let me view the link.They brand it as 'Social Networking';) Will have to check later...
Als
@Als: What? That's a lengthy C++ article on the private website of someone who knows what he's talking about, presumably _much_ to dry for anyone enjoying Facebook and the like. Just the Acknowledgments list is half filled with people who are well-known names in the C++ community. Oh my. Get a new job. Your current one is hindering your work.
sbi
@sbi: Yes i know, the filters at these place really suck!
Als
@Als: A censored net connection is really limiting to a developer. I'm with @sbi on this one. I hope they pay you enough to make up for it.
Matt Joiner
Don't forget restrict,VLA, type generic macro(tgmath.h)
Nyan
@Nyan: Yes, but the question was about features I *missed*. I almost added `restrict`, but I personally don't miss VLAs and `<tgmath.h>`.
schot
@Matt,sbi: feel like screaming "I am a developer, get me out of here!" ;-)
Als
@Als/@Matt/@sbi: I have to read half my pages via google cache :-/.
Tony
@Tony: Me too!!! Just somtimes even that doesnt work ;( and it is really frustrating, I am sure you would know
Als
@Tony, @Als: Wouldn't it help to officially for/report every unjustified block?
sbi
@sbi: Being a huge organisation, It is to much of a bureaucatic/administrative mess to get anything unblocked.Hundreds of approvals and frowns :(
Als
@Als: Yep, but that also means dozens of people have to look at your request hundreds of times and decide about it. When you know this, you could be relaxed about this and watch the bureaucratics process one of your request after another, until they themselves realize how stupid that is. Many, many years ago, when someone denied my vacation request for no other reasons than they ought to do it "by the book", I promised to handle everything "by the book" for a week. Once my issues had escalated two levels above those morons, I had my vacation signed. It felt damn nice to laugh into their faces.
sbi
+12  A: 

Not a feature in C, but arguably a killer feature of C is that the simple syntax of C89 makes it easy to write a compiler. Well, compared to a C++ compiler anyway.

Christoffer
+1. Just great.
sharptooth
Using C++, you could write a compiler almost exactly the same way, if you so chose.
Kaz Dragon
@Kaz Dragon: No, he means it is easier to write a C compiler than to write a C++ compiler in any language because C's syntax is much more simple.
JeremyP
I agree, though amusingly most of C++ awkward syntax comes from the fact that C++ aimed to be backward compatible :-)
Matthieu M.
@JeremyP - Oh right. I didn't read it that way around. I read it that it was easier to write a compiler in C. nm
Kaz Dragon
I would argue that the simplicity of the language benefits more than just the writers of compilers.
Nick
+29  A: 

Note: I guess I'll get flamed for this, but, then, it is a C++ question for C++ developpers, so...

What are the things that can be done in C but not in C++, and which of these features do you miss the most while coding in C++?

As a C++ developer, I miss nothing from C, be it C99 or otherwise.

I do not write this just out of spite. This is a question for C++ developers who miss some C/C99 features because they ignore basic features of C++. I do believe the question and its answers ignore viable or better alternatives in C++ (and no, the "C++ vector are nasty" comment is just a bogus reason).

This is why I will discuss here each one of the supposed "missing features"...

Variable-length arrays?

Variable length arrays is a language feature of C99. Its key advantages are:

  1. allocation on stack
  2. variable length on creation
  3. no need to deallocate

For the most common cases, std::vector will do the job, and have more features anyway. For example, unless I'm wrong, the variable-length array have the following disadvantages:

  1. allocation on the stack means you can't return a VLA from the function where it was declared
  2. the VLA can't be resized, meaning that if it's too small, then you're screwed
  3. VLA must be either declared at prototype scope, or block scope. It can't be extern, or static. And you can't declare it as a member of a struct.
  4. It cannot have an initializer

The vector can be resized, and can be returned. And with C++0x (and the r-value references), you can return a vector using move semantics, meaning no useless temporary object is needed. You can put it in a struct/class, it can be extern, or static. you can initialize it with a default value, the content of an array, a container, or, with C++0x, with an initializer list.

And even after that, if you really want something like the VLA, in C++, it is possible for an average C++ developer to write a stack-based vector-like container. And it would not need a full language committee update for that.

Just for the fun, I happened to post an answer with a simple proof-of-concept of a C++ VLA-like class.

C++'s vector is most of the time a better alternative, with more features. And in the rare case a VLA is really really needed, its features could be emulated by a user-defined class.

Casting void * into T *?

As for casting any void * into another typed pointer, this is not a feature of C missing from C++: This is a choice of weak-typing vs. strong-typing

And it's not as if it was impossible to do it in C++, as you can do it with a cast. The point of this difference is to decrease a bug risk in a language where void *is not as useful as in another: In my current C++ 100k lines project, I have zero occurrences of void *.

Designated initializers?

Constructors offers a better alternative.

Of course, you don't get the possibility of initializing directly the data in the struct, but then, data encapsulation means that most of the time, the data in my objects are private, so, the whole concept of using designated initializers to initialize them would be ridiculous.

As for POD-like structures, well, a constructor is easy to write, and can handle cases designated initializers won't ever do (like initializing members with non-zero values by default, or even calling functions).

Because C++'s focus on data encapsulation, constructors offer a better alternative to designated initializers.

Compound Literals?

This syntactic sugar supposes, again, that you know both the exact implementation of the struct, and have a public access to its members, which is something you usually want to avoid in C++.

Once again, Compound Literals are not something that can't be handled by a function, method or even constructor, with the advantage of bonus features, as described above.

Declare variable names that are keywords in C++ but not C?

I know how you feel: Each time I have the possibility of using interface, final or synchronized in C++, I get Java shivers, too...

:-P

Type-generic macro?

The problem in C is that you have quite a bunch of functions, doing the same semantic thing to different types, meaning the each function must have a different name. For example, according to the OpenGroup, the following functions do exist:

  • double sin(double x);
  • float sinf(float x);
  • long double sinl(long double x);
  • etc.

Source: http://www.opengroup.org/onlinepubs/009695399/functions/sin.html

But their names are a real pain to remember, so someone had an idea. Something about a macro which would use a compiler built-in extension to call the right one according to the types of the used parameters.

This is all the magic of C99's <tgmath.h>.

And the idea seemed so awesome that they even added a proposition to offer this feature for all functions in the next C standard, with something like:

#define sin(x) __tgmath(x,,,     \
float, sinf, long double, sinl,  \
/* etc. */                       \
, , sin)(x)

Source: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1340.htm

Now, the shocking news: This features is available in C++ since decades: This is called function overloading.

For example, the functions above are declared in C++ as:

  • double sin (double x );
  • float sin (float x );
  • long double sin (long double x );
  • etc.

So, the "Type-generic macro" is a hacked implementation, which strives to (partially) emulate the more generic C++ function overloading.

And guess what: You can even add your own overloads for your own user-defined types.

Conclusion

As shown above, each time I study a C99 feature, the conclusion is: "Hey, I already could do that in C++!" (and usually with the word "better" somewhere in the sentence).

Seriously, as a C++ developer, what I miss right now is to be able to use C++0x at work. For example, the following C++0x features:

  • auto
  • constexpr
  • initialized lists
  • r-value references
  • lambdas
  • nullptr
  • etc.

The whole "C missing features from C++" is an overrated concept which, I suspect, is more interesting to C developers (and C-with-classes developers) than C++ developers.

paercebal
These are fair points.
Matt Joiner
+1 I'm not a great fan of C++ myself, but I have some sympathy. None of the features C99 has that C++ doesn't have can be considered things you would really *miss*. So you can't implicitly cast to a void pointer? Oh no, better cancel the project then... or type seven extra characters `(void*)` (or whatever C++ programmers do nowadays to do casts).
JeremyP
@Jeremy: Implicit casting is prohibited in C++ for casting __from__ `void*`, _not to_.
sbi
@sbi: the point still stands though, doesn't it. It's not like explicit casting is prohibited.
JeremyP
@Jeremy: It's just that you were the second in this thread to saying that casting _to_ `void*` is restricted in C++. That is wrong. It's casting _from_ `void*` that is restricted - and for good reason.
sbi
+1. Well put. Though, you're not allowed to put your own overloads in the std namespace. You can, however, provide your own specializations of some of the templates (like std::swap).
sellibitze
@sellibitze : Thanks! Note that, usually, you'll make good use the ADL/Koenig's Lookup by adding an overload of a standard function (e.g. swap) in the namespace of your class. This way, this overload will be considered by the compiler. So usually, there is little consequences in not being authorized to play inside `std`.
paercebal
@paercebal: I'm well aware of ADL. Just wanted to point out that it wasn't clear what you meant by "you can even add your own overload..." It sounded to me like you were suggesting to put a custom overload in the std namespace.
sellibitze
These were fair points. Now you've changed them and they're not.
Matt Joiner
@Matt Joiner: you mean the sections on Type-Generic-Macros, Compound Literals, and the additional information on VLAs weaknesses and a possible C++03 implementation of VLAs are not fair?
paercebal
A: 

The main difference between C and C++ is that C++ is object oriented while C is function or procedure oriented. Object oriented programming paradigm is focused on writing programs that are more readable and maintainable. It also helps the reuse of code by packaging a group of similar objects or using the concept of component programming model. It helps thinking in a logical way by using the concept of real world concepts of objects, inheritance and polymorphism. It should be noted that there are also some drawbacks of such features. For example using polymorphism in a program can slow down the performance of that program.

On the other hand, functional and procedural programming focus primarily on the actions and events, and the programming model focuses on the logical assertions that trigger execution of program code.

jigar
You can write object-oriented C code (we do at work), object orientation is a design principle not a feature of the language. For an open-source alternative, I believe OpenSSL is reasonably object oriented.
Christoffer
I think this is a little recycled. One of the (few) great things about C++ is it doesn't force you to use OO.
Matt Joiner
@ Matt Joiner: neither does C force you to write OO code.
Martin York
@Martin York: I wasn't suggesting otherwise... Even this answer wasn't suggesting it. Relevance?
Matt Joiner
@Christoffer: OO is better when its supported by the compiler. When it is not, you'll end up doing by hand a lot of things that are done better by a compiler. And if you're not an über master of your language, then the code will be a pain to use and debug (not mentioning the learning curve). And best of the best: If you're writing your OO C code for a C++ compiler, then you *must* have missed something. In my case, I've seen a case of "Object Oriented C at work on a C++ compiler", and the result is far from pretty.
paercebal
@paercebal: Amusingly, OO in C++ is equally unpretty. And harder to debug.
Matt Joiner
@Matt Joiner: "OO in C++ is equally unpretty. And harder to debug" A C++ developer is supposed to know C++ OO. C++ OO is standard, which means that there is no "learning curve" associated with leaning an in-house framework mimicking OOP in a language that does not support it. And this is true for coding as well as debugging. Last time I checked (Visual C++), I was able to easily find the exact inheritance tree of an object while debugging with but a base pointer. Are you criticizing OOP in general, or OO C++? In the last case, what's so hard in OO C++ that doesn't happen too in Java or C#?
paercebal
+1 for stating simple truth that has triggered vote-down reflex of unthinking brutes
Alf P. Steinbach
Alf P. Steinbach
+1  A: 

As a fan of C, I think there might be another point in the concept of coding style, and that would be functional programming in contrast to object oriented programming known as OOP! for those who write their codes as statemachines it is a very interesting concept! Consider opengl as a good example. Also the speed of the running code is very better in C because of lesser memory references. You might also enjoy to hear that many programmers like to write their codes in C because of simplicity of design and how they are used to it (might not be that easy on syntax). Oh, and when you want to write codes very near to hardware level you should use pure C.

Green Code
Fact: C++ has the same access to hardware than C.__ Fact: One can use many styles of coding in C++. Including C-style of coding.__ Fact: C and C++ code will have the same speed, when the code is written by a decent coder.__ Fact: C++ is not about OOP. C++ is about multiple tools, including OOP, template metaprograming, procedural programming, functional programming. Which means that a C++ code is able to choose the best style for the task. Sometimes it is a C-like code. More often, this is a mix of paradigms. The key word here, is `choice`.
paercebal
Fact: "C-style" C++ is quite frowned on by C++ purists (read: language snobs). Note the "There is no language called C/C++" comments where questions are tagged with both. It's disingenuous to say "you can write C-style code in C++", when one who does so will more than likely be criticized for it.
cHao
@cHao: Sometimes, you gotta write sprintf in your C++ code. This remains C++ code if the sprintf is correctly encapsulated, and written to avoid its unsafe pitfalls. "C-style" C++ is more about procedural programming, using the C standard library, and it is not frowned upon (unless it is done carelessly). Now, avoiding constructors and using memset instead, using pointers to functions instead of functions or C++ signals, polluting the global namespace with functions and structures, and littering the code with char * instead of std::string is correctly frowned upon...
paercebal
@cHao: ... There are C patterns than should be written with care because they can cause bugs (pointers with no clear owners, void * and casts, pointers to functions, uninitialized structures, etc.), and it happens C++ has all the tools to write those patterns in one safe line. C++ developers choosing to ignore the C++ way in favor of the less safe C way are just asking for trouble. This is what is frowned upon.
paercebal
A: 

One of the missed features of C99 is the VLA, for which C++ is supposed to have no equivalent.

Some even questioned the possibility of writting in C++ a VLA-like object.

This is why I added this answer: Despite being slightly out-of-topic, it still demonstrates that, with the right library, a C++ developer can still have access to objects mimicking C99 features. And thus, that the features are not so missed than believed.

The main code is:

#include <iostream>
#include <string>
#include "MyVLA.hpp"

template <typename T>
void outputVLA(const std::string & p_name, const MyVLA<T> & p_vla)
{
    std::cout << p_name << "\n   MyVla.size() : ["
              << p_vla.size() << "]\n" ;

    for(size_t i = 0, iMax = p_vla.size(); i < iMax; ++i)
    {
        std::cout << "   [" << i << "] : [" << p_vla[i] << "]\n" ;
    }
}

int main()
{
    {
        MY_VLA(vlaInt, 5, int) ;

        outputVLA("vlaInt: Before", vlaInt) ;

        vlaInt[0] = 42 ;
        vlaInt[1] = 23 ;
        vlaInt[2] = 199 ;
        vlaInt[3] = vlaInt[1] ;
        vlaInt[4] = 789 ;

        outputVLA("vlaInt: After", vlaInt) ;
    }

    {
        MY_VLA(vlaString, 4, std::string) ;

        outputVLA("vlaString: Before", vlaString) ;

        vlaString[0] = "Hello World" ;
        vlaString[1] = "Wazaabee" ;
        vlaString[2] = vlaString[1] ;
        vlaString[3] = "Guess Who ?" ;

        outputVLA("vlaString: After", vlaString) ;
    }
}

As you see, the MyVLA object knows its size (which is a lot better than the use of the sizeof operator on C99 VLAs).

And of course, the MyVLA class behaves like an array, and is initialized by a size_t value (which can change at runtime). The only glitch is due to the nature of the function alloca(), meaning the constructor should be used only indirectly, through the macro MY_VLA:

Below, the code for the class, in the file MyVLA.hpp

#include <alloca.h>

template <typename T>
class MyVLA
{
    public :
        MyVLA(T * p_pointer, size_t p_size) ;
        ~MyVLA() ;

        size_t          size()                          const ;
        const T &       operator[] (size_t p_index)     const ;
        T &             operator[] (size_t p_index) ;

    private :
        T * m_begin ;
        T * m_end ;
} ;

#define MY_VLA(m_name, m_size, m_type)                                                      \
m_type * m_name_private_pointer = static_cast<m_type *>(alloca(m_size * sizeof(m_type))) ;  \
MyVLA<m_type> m_name(m_name_private_pointer, m_size)

template <typename T>
inline MyVLA<T>::MyVLA(T * p_pointer, size_t p_size)
{
    m_begin = p_pointer ;
    m_end = m_begin + p_size ;

    for(T * p = m_begin; p < m_end; ++p)
    {
        new(p) T() ;
    }
}

template <typename T>
inline MyVLA<T>::~MyVLA()
{
    for(T * p = m_begin; p < m_end; ++p)
    {
        p->~T() ;
    }
}

template <typename T>
inline size_t MyVLA<T>::size() const
{
    return (m_end - m_begin) ;
}

template <typename T>
inline const T & MyVLA<T>::operator[] (size_t p_index) const
{
    return *(m_begin + p_index) ;
}

template <typename T>
inline T & MyVLA<T>::operator[] (size_t p_index)
{
    return *(m_begin + p_index) ;
}

The macro is a mess, and could probably be better written. The class itself is probably not exception-safe, but it could be made to be. Anyway, it would need more code to be usable (i.e. handle the copy/assignment, make new/delete private, adding const wherever possible, etc.). My guess is that the end does not justify the time I would spend on it. So it will remain a proof-of-concept.

The point being "C++ can emulate C99 VLAs, and it could work even as a C++ objects array!", I guess I succeeded to demonstrate that.

I let the reader copy-paste-compile the code to see the results (I compiled it on a g++ 4.4.3, on Ubuntu 10.04.

paercebal
A: 

In C you can define a variable's name to delete. You cannot do that in C++.

Xolve
+2  A: 

If we ignore the obvious source of differences - C99 - restricting ourselves to C89/90, and also discard the trivial variants, like C++ keywords, there will still be some differences between C and C++

(1) You already mentioned the the ability to convert void * to any concrete pointer type without a cast.

(2) Function types with "unspecified" parameters, i.e. () in function type declaration. In C you can do this

void foo(int, int);
void bar(double);

int main() {
  void (*pf)();

  pf = foo;
  pf(1, 2); /* valid call */

  pf = bar;
  pf(5.0);  /* valid call */
}

This would not be possible in C++. Of course, one can also say that the general non-prototype function declarations is a feature of C, which is not present in C++ (applies to C99 as well).

(3) Some differences in array initialization with string literals: the trailing \0 is allowed to fall off in C, but not in C++

char str[2] = "ab"; /* valid C, not valid C++ */

(4) Tentative definitions in C, although they are mostly of no consequence.

(5) Another mostly inconsequential "feature": in C you can use value-returning functions that "forget" to actually return anything

int foo() {
}

The code is legal in both C and C++, but in C++ such function would unconditionally produce undefined behavior. In C the function would produce undefined behavior only if you actually attempted to use the returned value

foo(); /* fine in C, undefined behavior in C++ */

(6) Some other stuff I'll add later if I remember it.

AndreyT
Do you really miss those features ?
paercebal
@paercebal: Miss? I work mostly in C these days, so I don't get to "miss" them. In any case, whether anyone misses these features is beside the point within the context of the OP.
AndreyT
@AndreyT: My bad. There are TWO questions: The questions are "What are the things that can be done in C but not in C++, and which of these features do you `miss` the most while coding in C++?"... I guess I focused on the `miss` part, reading "things that can be done in C but not C++ that you miss while coding in C++"...
paercebal
@paercebal: OK. Well, normally I don't really use any of these features (besides `void *` conversion) in my C code at all, so I wouldn't probably miss any of them if I worked in C++.
AndreyT
`void *` conversion is used a lot in my C too
Matt Joiner
A: 

What i like in C is the ability to say look at something like a = b; and know exactly what it's doing. In C++, anyone can override operators, meaning a simple statement like that could end up calling some massive copy constructor (or worse, something totally irrelevant). You see a = b; in C++, you have to guess (or go and look up) whether someone's done that just to be annoying.

cHao
This is a "The world is full of saboteurs!" syndrome. You don't trust either your colleagues (or your library provider), or the language itself. If you work with people who will do something irrelevant to semantic context (like overloading a `+` and code a `-` inside) and who will do that "just to be annoying", then you should search another job. Coding in C++ with normal people can be quite enlightening: In 10+ years of career, I never worked with the morons you describe, and when some code is inefficient, most of the time, it is NOT in the operator overloading code.
paercebal
... Now, the `a = b` example is a good one. In C++, this means that `a` will become a copy of `b`. If `b` is a large object, then you can bet the copy will be expensive. The important part here is the "if `b` is a large object". If we ignore the "saboteurs" conspiracy theory, this means that in C++, the type is important, whereas in C, the importance is in the functions. This is why I wrote "trust the language". To work correctly in C++, you need to switch from the "procedural" to the "objects should behave" viewpoint. Without this switch, then all you're seeing is hostile code.
paercebal
My issue is more that i can't look at inefficient code and *see* that it's inefficient, because of the abstractions that C++ and OOP together provide. (I don't expect sabotage, but i do expect that a lot of times they will make the CPU jump through more hoops than absolutely necessary to get my particular need filled.) At the same time, i can't just trust the abstraction, because in some cases (`std::endl`?) it can lead to even more waste. There's a strange middle ground you have to tread with C++, caring about some details and not others, whereas in C it's clearer where the pitfalls lie.
cHao
@cHao: Your "i can't look at inefficient code and see that it's inefficient" pattern only works on C operators. For everything else, it is useless. And in C, this means most of the code, as the operators, by definition, do almost nothing. The conclusion is that, like everyone else, if you need to measure the performance of some code, you need to profile it (or look at the source, and guess it).
paercebal
@paercebal: And in C++, it potentially means *all* of the code. The fact that C operators "do almost nothing" can be a good thing. It means fewer things to have to worry about, when you don't have functions disguised as operators. Don't get me wrong; i tend to like the expressiveness that operator overloading can provide. But at the same time, it kills the "operators do almost nothing" rule. And that rule is one of the things i like about C: that `a + b` or `a = b` or `a(b)` is what it looks like, and is not a huge operation, and won't change its meaning based on what it's operating on.
cHao
@cHao: You're right about "...won't change its meaning based on what it's operating on", which is another way of saying "in C++, the type is important, whereas in C, the importance is in the functions". It's strange to have two languages who have so much in common to become, in the end, so different. I guess this "weak-typing vs. strong-typing" and/or "type vs functions" difference are what makes us disagree, albeit somehow still both being right in the context of each language.
paercebal
A: 

There are a few subtle differences in syntactic sugar and type abuse, but they're trivial to work around.

The most important capability of C is to generate completely free-standing programs with absolutely no external dependencies. This is why operating system kernels are almost universally written in C. C was actually designed for implementing operating systems. It is possible to write OS kernels in a restricted subset of C++, but enforcing those restrictions only happens at link time, if at all, so it's much more of a pain to deal with than the minor syntax differences.

Chris