

Why artificially limit your code to C? - ekm2
http://stackoverflow.com/questions/649789/why-artificially-limit-your-code-to-c

======
comex
The fact that C++ is almost a superset of C is commonly used as an argument
for C++, and the accepted answer in the post is a common response - C++ is not
quite a superset of C, you have to cast malloc, you lose out on C99 features,
etc. But I think it misses the point: if you could really get the advantages
of C++ by using its features in a few necessary places in your C code, I think
it would be worth it to make your code slightly uglier to accommodate it.

You can't.

Generic containers are probably the C++ feature C is most sorely lacking. But
as soon as you start using map<> in your code, you have to deal with slower
compilation in all the files that use it (if a map is declared in a header
file, e.g. as a struct member, that could be quite a lot), repetitive code
generation the linker might or might not optimize, verbose syntax
(std::map<struct foo *>::iterator, yay), and the requirement (more or less) to
use new instead of malloc for any struct that contains a C++ object. And if
you want your map's performance to not suck, you'll need to depend on either a
nonstandard extension or C++11 to get hash_map/unordered_map.

Then there's writing templates - even in the context of C++, template code
tends to be hideously ugly (template<typename T> everywhere, the
aforementioned issues with code generation and sticking everything in header
files, pages of confusing error messages when you mess up), and is hard to
debug with a debugger. Trying to use them with C can only lead to pain -
especially since they work best when you have actual objects to specialize on.
Templates do allow certain C code to be written more nicely, such as binary
formats where there are multiple versions of the same struct, but even then
there are limitations to the magic - template-ness tends to spread to callers.

gcc apparently wanted to switch to C++ partly in order to use destructors: now
you have spooky action at a distance, where the caller of your method is a
closing brace, thanks to a declaration a page away somewhere up in the
function.

Do you want to use a few classes to add some structure to your code? It will
certainly start to seem a bit forced to declare struct foo and functions like
foo_alloc and foo_get_bar once you're in C++, when declaring a class expresses
the concept more elegantly. And then you're stuck with C++'s context sensitive
nature (anyone who understands the code will know that it->getName() is a
reference to Foo::getName, and fooCount used here is a member variable, so
it's fine, right?) and poor separation of interface and implementation (it
really doesn't make sense that you have to declare private fields in your
header file, and it doesn't make compilation any better), and if you're not
careful your code will start to feature a vector of objects where an array of
ints is appropriate, or yet another method whose only purpose is to pass on
slightly different arguments to a method of a member variable.

C++ programmers accept these issues in exchange for a high-level coding style
(less security bugs!) and an easier time writing clean code than C programmers
(although bad C++ code is a whole lot worse than bad C code). You will gain
hardly any of that by sprinkling C++ into C. Solving these problems in C
sometimes leads to more work and more verbose code, but the result is also
often a better solution. If you absolutely must have code generation, use a
macro, they're not as bad as C++ programmers make them out to be - or, at
least, they're ugly enough that most programmers know to use them very
sparingly. (I'm rather a fan of <sys/queue.h>, for example, although you do
have to understand how it works to make sense of code that uses it.)

~~~
ExpiredLink
> where the caller of your method is a closing brace

Although I agree with the sentiment of your comment destructors and RAII in
general are arguably the best C++ features.

If I were forced to use C++ again I would restrict my code to a lightweight
subset of C++, especially I would not use the C++ Standard library (STL,
iostreams, string) and of course not use BOOST (or any template heavy library)
and C++0x. But I would definitely include 'full-fledged' exception handling
from the start.

~~~
wladimir
What would you use for string handling, then? Please don't tell me you prefer
strcpy/strcat and zero-terminated strings?

~~~
cygx
Depending on the use case, libc, Windows API or ICU.

Personally, I'd like to see a simple C string library using modified UTF-8 (to
be compatible with ASCIIZ) which is grapheme aware.

I'm tempted to take a shot at writing one myself, but haven't gotten around to
it yet. If anyone is interested, see
<http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries> for the
algorithm and
[http://www.unicode.org/Public/UNIDATA/auxiliary/GraphemeBrea...](http://www.unicode.org/Public/UNIDATA/auxiliary/GraphemeBreakProperty.txt)
for the property data...

------
huhtenberg
> _C is small and simple and I can fit the whole language in my brain_

Except when you see Duff's device for the first time and realize that C you
thought you knew what's the actual C :)

<http://catb.org/jargon/html/D/Duffs-device.html>

~~~
Jach
Go one step further and use Duff's Device to implement coroutines!
[http://webcache.googleusercontent.com/search?q=cache:pA85c1U...](http://webcache.googleusercontent.com/search?q=cache:pA85c1UFn-4J:www.chiark.greenend.org.uk/~sgtatham/coroutines.html)

~~~
DiabloD3
Dear HN: Please give me more upvotes per comment Signed, people who are truly
impressed by this absurd abuse of C

------
renata
I work on aviation software. We have to use C because C++ generates too much
code behind the scenes for you. If you don't create a constructor or
destructor, there is an implicit one created. Templates are instantiated once
for each type, but we still have to prove that (and test each instantiation).
We'd also have to certify a new compiler, since our current one only supports
C.

My point is basically that in domain-specific cases, C can be a good choice
because of the lack of sugar and simplicity. I doubt this applies to most
cases though.

------
TheNewAndy
No one there mentions symbol scrambling, and how it makes C++ libraries
unportable across multiple compilers for the same platform.

~~~
pjmlp
Everyone loves to bash the lack of a C++ ABI. Now please name another language
with native implementations with a standard ABI across different compilers.

C implementations have a standard ABI, because they usually are the operating
system ABI.

~~~
TheNewAndy
I'm not sure what you mean here by "name another language". Do you mean other
than C? I don't understand what that would demonstrate.

~~~
batista
That it's not that common?

~~~
pjmlp
No, because language standards only specify the language itself not the
implementations.

So each vendor comes up with its own library format and tricks how to make the
language usable in dynamic libraries. And as far as I know, they seldom talk
among themselves about common ABIs.

C ends up being used as universal ABI, because in the end all implementations
that generate native code need to interface with the operating system, which
usually is developed in C.

But this was not always like this. Before C won its place as system
programming language outside the UNIX world, there were other systems
programming languages in use. On those systems there was no C ABI as such.

The Pascal calling convention ABI exists, because on the early 80s a few
operating systems were developed in extended version of Pascal, like the first
MacOS, for example.

------
kabdib
You have a large body of code that is using C just fine, thanks, and moving it
to C++ (while probably "trivial" for some meaning of trivial involving a few
weeks/months/years of refactoring) would expose you to every C++ yahoo's whim.

"I wanna use maaaaaap! Why can't I use map? Map map mapmaapmap."

"Because this stuff runs in an interrupt handler, and is shared with thread-
world code through a very carefully designed API involving a couple layers of
synchronization. Many Bothans died to make this work well, and fast."

"No map?"

"No map. Go read about NUMA."

"What about streams?"

[buries head in hands]

tl;dr; It's an idiot shield. Kids, get off the lawn :-)

------
sanxiyn
C++ is not a superset of C, therefore using C as C++ needs porting. It's fine
if you consciously restrict yourself to C++-compatible subset of C (GCC
warning -Wc++-compat can help you), but if you don't it can take a significant
effort.

For a realistic case of compiling large C codebase not written in
C++-compatible subset of C as C++, take a look at GCC. I think it took
something like 6 months to compile GCC as C++ regression-free.

<http://gcc.gnu.org/wiki/gcc-in-cxx>

------
fauigerzigerk
The question is pretty weird in the first place. If I like a particular
language, why would I automatically like some arbitrary superset of that
language?

But there are many practical reasons as well. One that hasn't been discussed
much is exceptions. In order to use C++ libraries in C code you'd have to
"RAIIfy" your entire codebase. That means wrapping all dynamic memory
allocations in their own objects and replacing malloc with new. What's left of
C after doing that?

Switching off exceptions on the compiler level isn't a viable solution either
because it leads to undefined behavior.

------
drucken
Detailed comment on that stackflow thread says it all: _life is short_ , use
C.

