28

Is using C in C++ bad?

Many people have told me that using C in C++ is bad because it's not as safe, and it requires more memory management. I keep telling them that as long as you know what you're doing, and you delete your "new"s and free your "malloc"s then C isn't a problem.

I'm currently on a forum where an argument over std::string vs. a char* is taking place. Some people are saying that allocating a simple char* memory block is more efficient, and as long as you deallocate it, it's fine. On the other hand we have people saying that std::string is superior because it has no memory management involved but is less efficient.

So the main question here is:

  • Is mixing C/C++ bad? Should you ONLY use 100% C++ when you're coding C++?

Any answers would be appreciated!

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Brad
  • 10,015
  • 17
  • 54
  • 77
  • 1
    C++ is a superset of C. Therefore, any valid C program is a valid C++ program, and there is no such thing as "mixing" C into C++. – Jonathan Oct 26 '10 at 16:54
  • I imagine he's talking about c features which have been deprecated in c++, like malloc – Sam Dufel Oct 26 '10 at 16:55
  • 35
    @Jonathan: `int main() { int class = 2; }` (valid C, not valid C++) C++ is not a superset of C; C and C++ share a common subset. – James McNellis Oct 26 '10 at 16:55
  • 9
    @Jonathan: Oh, come on, you know perfectly well what he's talking about. No one can ever convince me that printf is a C++ function. Ever – Armen Tsirunyan Oct 26 '10 at 16:56
  • @James: Virtually all Annex C of C++2003 :) – Armen Tsirunyan Oct 26 '10 at 16:57
  • @Armen... how about std::printf? – Gerald Oct 26 '10 at 16:58
  • @Gerald: Are we going to pretend further that we have no idea what is meant? :) – Armen Tsirunyan Oct 26 '10 at 16:58
  • C++ FQA to the rescue: http://yosefk.com/c++fqa/mixing.html – Nick T Oct 26 '10 at 17:00
  • @Armen... I know perfectly well what the OP meant. And I kinda know what you meant, but I completely disagree with you. – Gerald Oct 26 '10 at 17:01
  • @Gerald: My point is that a programming language is not a syntax. It's a paradigm. I know that C++ is a multiparadigm-language. But why use an older/unsafer paradigm *for no good reason*? Of course if the profiler tells you that changing streaming to printf will boost the performance, do it, but never otherwise. That's what I kinda mean :) – Armen Tsirunyan Oct 26 '10 at 17:05
  • 4
    By "mixing", do you mean implementing some parts of your project in C, and some parts in C++, with a clean separation between the two languages? Or do you mean (as your third paragraph suggests) blending idioms from the two languages to make a ghastly hybrid language? – Mike Seymour Oct 26 '10 at 17:06
  • Firstly, I was being facetious, although I suppose I could have been clearer. Secondly, unless a profiler tells you that your code is inefficient, do whatever is clearest in your chosen language. If `malloc`/`free` makes the most sense, use it. If using `std::string` makes more sense, go with that. – Jonathan Oct 26 '10 at 17:12
  • 2
    @Nick T: If the FQA is ever useful in resolving a question, it must be a really, really strange question. Either that, or you don't want an answer that's true. – David Thornley Oct 26 '10 at 20:56

12 Answers12

23

I keep telling them that as long as you know what your doing, and you delete your new's and free your malloc's then C isn't a problem.

This is true; if you are extraordinarily careful and ensure that you manually clean things up, then it isn't a problem. But do you really have the time to do that? Every call to new can throw std::bad_alloc. Do you always catch every exception that can be thrown and manually clean up any resources?

I'd hazard to guess the answer to that is "no," because it is very tedious to write code like that and it is difficult to be absolutely sure that code written like that is correct, even in the case of rare failures.

If the answer is "yes," then why are you wasting so much time worrying about resource management? C++ idioms like scope-bound resource management (SBRM; more commonly known as resource acquisition is initialization (RAII)) and libraries like the standard template library are there to help you write correct code more easily. Why do things the hard way when you don't have to?

Should you ONLY use 100% C++ when your coding C++?

Yes, though if there is a C library that does something you need, or if you have legacy C code that you want to use, you can certainly use that code; just be sure to be careful. Often the cleanest way to interop with C code is to write a C++ wrapper around it.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 2
    i don't see anything in your answer specific to 'C in a C++ project'. your arguments seem just against C in general, and therefore fall in the 'pick your poison' land. – Javier Oct 26 '10 at 17:02
  • 1
    @Javier: No, my answer is specifically about using C in C++ code. There are no exceptions in C, so you always know when a function may return and you always know when you have to clean up resources (barring some crazy usage of `longjmp` or something like that). It takes a bit of work to manually manage resources in C; it's all but impossible in C++. – James McNellis Oct 26 '10 at 17:03
  • 2
    oh, right. exceptions are a big reason not to call C++ from C. but calling C from C++ is ok (and far more common) – Javier Oct 26 '10 at 17:06
  • @JamesMcNellis FFWD to 2018 :) I would like to add a single C file to my CPP project in the always up to date VS2017 ... So... What version of C that is, in that C file? I can see it not cpp, but I can see it is not C99 too .. Is there a way to tell? –  Sep 14 '18 at 10:50
13

My strong belief is that your question doesn't have to do with C or C++ at all. Your question is about trading dubious efficiency for safety. Yes, C can be more efficient. But how much more efficient? And what do you pay for that? These are the questions you should answer. In most cases string vs. const char* overhead is unnoticeable. If you are developing an efficiency-extremely-critical application, then why not code it in C in the first place?

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • 1
    strictly speaking, with C++ you get added bells and whistles (and these don't necessarily reduce performance) - but there are times when you have to sacrifice standards for raw performance (sprintf vs. iostreams, atoi (& friends) vs lexical_cast etc.) – Nim Oct 26 '10 at 17:00
  • @Nim: There are such times, but such times are extremely rare. And comprise a very small part of our whole code. If the whole application is so time-critical, why not use assembly or C? That's my point – Armen Tsirunyan Oct 26 '10 at 17:02
  • there are many personal reasons to like C over C++, performance is a very minor one. when doing C++, i prefer to do it fully C++; but i really understand distaste for lots of things. incidentally, std::string is one of my least favorites, give me a char* anytime. – Javier Oct 26 '10 at 17:04
  • You think you should write an entire game engine in assembly language, just because you need the performance of assembly for a handful of math functions? – Gerald Oct 26 '10 at 17:08
  • @Gerald: I think that unless it has been proven that low-level/unsafe/ugly(arguably) code (be it assembly or C) will gain significant benefit in efficiency which is needed for this program (which it can also not need) one should not resort to it. – Armen Tsirunyan Oct 26 '10 at 17:11
  • @Javier... I have a hard time understanding how you could possibly prefer char* over std::string. In what way? Do you really prefer using strcat instead of +? – Gerald Oct 26 '10 at 17:15
  • @Armen... Of course I agree with you. But sometimes it IS needed, and it is better to mix in a little bit of low-level/unsafe/ugly code, than to write the whole thing in low-level/unsafe/ugly code. – Gerald Oct 26 '10 at 17:16
  • @Armen, but why when you can combine "best" of both? IMHO, I think to take an extreme viewpoint on this implies that to an extent you're blinkering yourself, there is no black and white here, and you should look at what makes most sense when you need to use it, and then use it... – Nim Oct 26 '10 at 17:18
  • @Gerald/@Javier, + is horrible, but then strcat isn't ideal as well, but std::string offers so much more (append, assign, insert etc.) When used correctly std::string is pretty funky, however *most* beginner/intermediate developers (and I class myself in this group) tend to abuse it, and hence it's reputation... – Nim Oct 26 '10 at 17:27
  • @Nim: How do most beginner and intermediate developers abuse `std::string` and what reputation does it have? – James McNellis Oct 26 '10 at 17:36
  • @Gerald: it's part of the cleanliness of C vs the opacity of C++. of course i don't use strcat() on real apps, but a good basic string library (that i reuse a lot) is less than 100 lines of readable C. – Javier Oct 26 '10 at 17:47
  • @James, okay may be "abuse" is a strong word, shall I say, mis-use; say for example: multiple concatenations using the global operator+? it's easier to type but what's happening under the covers?? If it didn't have a negative reputation, discussions of this nature would not exist... – Nim Oct 26 '10 at 17:58
  • @Nim... other than a small performance hit caused by the creation of additional string objects, what is the problem with using + for multiple concatenations? In many cases it's more readable than using append, and more type-safe than using a string stream (try streaming an MFC/ATL CString to an STL stream and see what happens.) – Gerald Oct 27 '10 at 02:58
  • @Nim, @Gerald: C++0x has addressed the issue with creation of additional objects using + for multiple concatenation (move constructors, rvalue refs etc.) – Armen Tsirunyan Oct 27 '10 at 06:45
  • 1
    @Gerald, at least in my space, this "small performance hit" is relatively high compared with everything else that's going on, so for us it's a big problem, but some of it can be alleviated via the other functions of std::string without having to resort to char*! Don't get me wrong, like I said, I like std::string, all I'm saying (and have been all along) is that you shouldn't restrict yourself to one or the other... @Armen, C++Ox addresses lots of useful things, but in the production environments that I'm familiar with, upgrades to take advantage move at a glacial pace.. – Nim Oct 27 '10 at 08:11
  • @Nim... but you seemed to be calling the use of + for concatenations a "misuse" (and horrible), when we all seem to agree that premature optimizations are the work of the devil. Obviously if you find noticeable performance problems with it's use, you would want to look for something faster in that situations, just like everything. That doesn't make it horrible, it makes it convenient at the cost of a relatively small performance hit that doesn't make a difference in application performance for most uses. – Gerald Oct 27 '10 at 14:40
  • @Gerald, agreed that root of all eveel is premature optimization, however I am merely commenting on plain laziness (hence misuse IMO), when clearly there are functions in std::string which are better suited for everything that you're likely to do with +. At the end of the day, it's just an opinion, and am not trying to inflict it on anyone else, merely expressing it! :) – Nim Oct 27 '10 at 15:16
12

I'm genuinely surprised by the polarization in the answers and comments thereof.

In my eyes, the answer is pretty simple:

When writing a C++ project, use C++, avoid C ( and family) and stick to the Standard Library and STL. Ensure a homogenous C++ interface (it is a C++ project after all!) When using an external project in C, which happens to be written in C, of course you can use it. (see examples below)

Two prime examples:

  1. Write a C++ program/library that does scientific calculations. I would definitely use GSL (GNU Scientific Library), and it is written in C. There are only a few caveats (like specialized initialize and free functions for specific structs and functions within GSL), that can be absorbed in a std::unique_ptr typedef. There is also the issue of error handling: checking error codes can be abstracted away in an exception mechanism if necessary/wanted, or you can keep the error codes contained within the calculation functions. GSL does have a way of setting up an error handler, I imagine some other C libraries have such a functionality.

  2. Writing a C++ program using the Win32 API, which is horribly C based. I'm talking about light API usage, like reading the files in a directory, checking if a file exists, etc., not heavy GDI+ or other stuff. I like to wrap all the C functions the Win32 API exposes in nice C++ style functions, perhaps with the necessary exceptions and returning a std::string instead of having to pass a char* buffer as argument.

I understand both examples are quite... shallow... but I feel they express a general enough idea.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
5

Yes it's bad to mix C and C++, and the reason has nothing to do with performance or security:

It is bad cause of a maintainability:

  • a C++ programmer expects all code to behave like C++.
  • a C programmer expects all code to behave like C.

So when you mix C++ and C, you break both programmers expectations on how things should work.

ph_0
  • 617
  • 8
  • 27
UnixShadow
  • 1,222
  • 8
  • 12
4

The answer is, of course: it depends.

Generally you want to avoid mixing things that can cause confusion, that can further lead to hard-to-find bugs. Just because "you know what your doing" doesn't mean that the next person to touch your code will know what you were doing. If you're developing code that only you will ever use, then it's probably okay, but that's rarely the case.

Using C for performance is fine if you're careful. But you should only do it if you KNOW that you need the performance. Premature low-level optimization is the work of the devil.

It's a very rare case where using char* over std::string will give you any noticeable performance benefits, and it's only worth the memory management hassle in those cases where it does for sure.

Gerald
  • 23,011
  • 10
  • 73
  • 102
2

Regarding the argument over std::string vs char*:

std::string is not going to be slower than char* (for heap char*); many implementations are much faster because they use private memory pool. And anyway the robustness of std::string far outweighs any (unlikely) perf hit.

ph_0
  • 617
  • 8
  • 27
pm100
  • 48,078
  • 23
  • 82
  • 145
  • And even if the implementation *isn't* faster than using C-style strings, the utility of the `string` class makes up for any loss of performance IMO. Don't trade maintainability and readability for performance *unless* you're failing to meet a hard performance requirement **and** you've already performed all the high-level optimization you can. – John Bode Oct 26 '10 at 18:10
2

The better question here is, why use C? The performance? Firstly, I believe that there is no measurable performance difference for a program with the same function. Secondly, you would have to profile and prove that for your specific case, C++ is slower. Thirdly, you're giving up a huge quantity of application security by using C instead of C++.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 2
    Depends on how you do it. I never dug into the source code, but I found that for a particular use Boost.Regex, which is developed in C++, is approximately 100 times slower than PCRE for regex matching in long strings. Presumably this is a higher-level performance problem in the design, but it's probably that way because of the way it sticks to generally "accepted" C++ idioms. You simply HAVE to operate on raw C-strings there to get optimal performance. – Gerald Oct 27 '10 at 04:01
  • @Gerald: That's a very different thing. First, you actually measured, and determined that boost::regex is slower than PCRE. I presume that you then went on to determine that this was an actual performance problem in your application. Then you went and used PCRE. And if boost::regex was your own code, you only then went and used PCRE if you determined that boost::regex could not be fixed or optimized further. – Puppy Oct 27 '10 at 10:06
  • 1
    .. true. I was just being a little pedantic in regards to your statement that "I believe that there is no measurable performance difference for a program with the same function." There can be, depending on how much you stick to "C++-ness", or something like that ;) – Gerald Oct 27 '10 at 14:45
1

The simple answer here is, profile; determine which works best in your case and use it wisely!

Nim
  • 33,299
  • 2
  • 62
  • 101
1

Is using C in C++ bad?

although a subjective question: in my opinion, take great measures to avoid using c in c++ programs.

Many people have told me that using C in C++ is bad because it's not as safe, and it requires more memory management. I keep telling them that as long as you know what your doing, and you delete your new's and free your malloc's then C isn't a problem.

you're reintroducing deficiencies and dangers c++ was designed to overcome, and it's not the way things are done in c++ programs.

i routinely check/reject/rewrite code that enters codebases that is "c with c++ features", or "c++ with c features". i even go as far as to change malloc, free, etc. to assert in root namespaces (among other things).

I'm currently on a forum where an argument over std::string vs. a char* is taking place. Some people are saying that allocating a simple char* memory block is more efficient, and as long as you deallocate it, it's fine. On the other hand we have people saying that std::string is superior because it has no memory management involved but is less efficient.

there are more options for representing a string in c++ than std::string.

in my opinion, it's completely valid to create a new class which represents a string and serves a particular purpose, or follows additional contracts (when necessary). part of the contracts of such string representations are (of course) that they manage their own resources using new[]/delete[] when dynamic memory is used.

if efficiency is that important and std::string is less than ideal for a specific task, then c++ is powerful enough to express your intent for these specific cases by creating a specialized interface in c++. there are plenty of cases where this is acceptable (imo), but not always worth the time investment. in any event, it's easier to manage than integrating c idioms/styles/dangers into c++ programs.

So the main question here is: Is mixing C/C++ bad? Should your ONLY use 100% C++ when your coding C++?

it's best to create reusable object based solutions for your needs. the dangers in the example provided can be completely encapsulated (if this optimization is truly worth the time investment), and be written to use c++ idioms, without performance loss and with better maintainability.

justin
  • 104,054
  • 14
  • 179
  • 226
1

In the specific case of string versus const char *, you should use bare const char * for all variables that hold string constants (and only string constants), converting to string only when passing to an API that requires string. Doing this consistently can eliminate enormous numbers of global constructors, does not cause memory allocation headaches (since string constants are permanent, constant data) and IMO actually makes the code clearer - you see const char *, you know that's gonna be a string constant.

zwol
  • 135,547
  • 38
  • 252
  • 361
1

If your'e talking about techniques, I'd be careful to say that doing the above is okay.

Writing C++ programs using C-style program organization techniques will likely result in lots of maintainability issues. In general, the programmer is ignoring many of the benefits that an object-oriented language provides. Simply because much of C syntax is valid C++ and many coding techniques transfer does not mean you should do them in C++.

That said, using C functions and things isn't a problem, so long as your'e careful about their use. In some cases, you have to.

J. Polfer
  • 12,251
  • 10
  • 54
  • 83
0

Well, I'm in a strange situation. I am working on a system that is supposed to be in C++ (C++ compiler is used and term C++ is used), but everything is written in C. This is very frustrating, because it is getting to a point where I have to 'prove' C++ is better to use than C, even though we are coding in C++. It was all hell when I introduced std::string. My take on it is that everything now is starting to get cluttered (mixing of C and C++). There are rare instances of error handling. In fact, I think I can count 3 system wide try-catch statements. The code is messy, memory leaks are prominent and finding an error is a needle in a haystack. There are hundreds of lines of code that can be replaced by C++ functions. I'd say writing the code is more efficient, cleaner and easier to understand.

From my experience, yes of course you can mix C and C++. You can pretty much do whatever you want, but maintaining, debugging and actually figuring out what's going on becomes a problem. It's easy to say you're going to clean-up your memory allocations, but maybe someone else uses your code and doesn't. Maybe you forget to do it and you waste hours on finding silly bugs, instead of using that time to do something productive. I don't even think there should be an argument. When you do C++, do C++. When you do C, do C.

Jan Swart
  • 6,761
  • 10
  • 36
  • 45