Using printf in C++

G

Guest

The impact of RTTI on performance is greatly exaggerated by people who
haven't actually tested it, but base their claims solely on assumptions
and impressions.

I have actually tested in practice the speed difference between calling
a regular function and a virtual function.

RTTI != virtual function

was your virtual function being called polymorphically? Because if it wasn't any reasonable compiler would call it non-virtually
 
R

Richard Damon

Could someone please post a practical example of this mythical "code
bloat" caused by templates, and a better alternative?

(And "practical" above means not artificially contrived to be as
pathological as possible by using completely unconventional code that
no sane programmer would ever write.)

Note that as many "rules" based on performance, things change over time.
When C++ was young, optimizations like the linker folding two identical
functions was unheard of. In one sense, because of the level of this
problem, implementations have spent a lot of effort to relieve much of
the issue.

You can still have cases where a template function has a significant
piece that could be factored out as common over many types, but because
the programmer only sees it in the code once, they don't think about
factoring that code out, or that there are piece that COULD be factored
out with small implementation changes, but because the code is only
written once, the need doesn't present itself to the programmer.

Without knowing details of how good an implementation is, you don't know
how much output code a template is going to create when implemented many
times. Thus, especially in the hands of a junior programmer, there is a
danger that it is possible to generate this bloat without obvious signs
in the program.

Like most of these "rules", they are primarily aimed at the junior
programmer who is still learning what works well and what doesn't, and
were rarely intended to be "hard" rules that all programmers must obey.
Note that this rule begins with "Naive" and has "may", which basically
just says, think about before just throwing in a template, to make sure
you understand possible ramifications. The senior programmer likely has
developed the intuition to recognize these and has less need for them as
formal "rules"
 
P

Pavel

Martin said:
Luca said:
Le 13/05/12 20:33, Luca Risolia a écrit :
All that stuff can be written in a more readable, type-safe code by
using std::clog (or whatever stream you need) and standard manipulators.

Great!

Go ahead, and show us how.

if (p_num_breakpoints> 0) {
clog<< "Breakpoint Address Core Enabled?\n"
"---------- ---------------- ---- --------\n";

for (size_t b = 0; b< p_num_breakpoints; b++) {
const s_breakpoint *bpp =&p_breakpoints;
ostringstream core;
bpp->b_core == -1 ? core<< "All" : core<< setw(3)<< bpp->b_core;

So, what's the advantage of this code, which is longer, more complex (counted,
for example, as the number of tokens even when adjusted with the number of
format specifiers from printf code) and unnecessary dynamic memory
[de]allocations dynamic inside the loop (which may start having quite
interesting performance implications for a process compiled with thread-safety
options somewhere in the middle of production) over the original code does not
do any of it?

Also, the output statement does not relate intuitively to the header so counting
all these setw arguments would make me feel dumb (for doing a stupid job that I
could have avoided if I used the right tools).

-Pavel
clog<< setfill(' ')<< setw(3)<< ' ' // indent
<< setfill('0')<< setw(2)<< b
<< setfill(' ')<< setw(8)<< ''
<< setfill('0')<< setw(16)
<< hex<< reinterpret_cast<unsigned long>(bpp->b_address)
<< setfill(' ')<< setw(2)<< ''
<< core.str().substr(0, 3)<< ''
<< setfill(' ')<< setw(3)<< ''
<< boolalpha<< static_cast<bool>(bpp->b_enabled)
<< '\n';
}
}

..which produces the same output as the original version with printf():

Breakpoint Address Core Enabled?
---------- ---------------- ---- --------
00 00007fff7f886a0c All false
01 00007fff7f886a0c 12 false
02 00007fff7f886a0c 123 true

I thought the output was supposed to look like this. (Obviously it
wouldn't take much to change it to this).

Breakpoint Address Core Enabled?
---------- ---------------- ---- --------
0 00007fff7f886a0c All No
1 00007fff7f886a0c 12 No
2 00007fff7f886a0c 123 Yes

[snip]

Martin Shobe
 
P

Pavel

Juha said:
Could someone please post a practical example of this mythical "code
bloat" caused by templates, and a better alternative?

(And "practical" above means not artificially contrived to be as
pathological as possible by using completely unconventional code that
no sane programmer would ever write.)
Not to blame templates in general for code bloating (bloating compilation time
is another story; for whatever reason no one here complains about this one), but
the above ostream code (and any iostream code, in my experience) certainly
bloats the code at the call site as compared to printf code as it emits many
extra function calls and object constructions on top of 2-3 function calls taken
by printf.

Just for my own interest, I composed two roughly equivalent printing functions
from the above example into a little program (see below), compiled it with g++
4.6.3 on 64-bit Linux, optimizing for size:

g++ -Os -o pvocs pvocs.cpp

and measured the functions from 'objdump -d' dump.

the size of printfOutput() is 0x400f22 - 0x400e74 + 1 = 175 bytes
the size of ostreamOutput() is x401146 - 0x400f23 + 5 = 552 bytes


The last addition of 1 or 5 is for the length of the last command whose address
I have in the dump. It is instructive that printOutput() ends with a simple
1-byte retq instruction:

400f22: c3 retq

whereas ostreamOutput() ends with 5-byte call of (obviously long-jumping) C++
stack-unwinding stub

401146: e8 c5 fb ff ff callq 400d10 <_Unwind_Resume@plt>

where _Unwind_Resume strains CPU pipeline a couple of extra times and loads a
few extra cache lines:

0000000000400d10 <_Unwind_Resume@plt>:
400d10: ff 25 82 13 20 00 jmpq *0x201382(%rip) # 602098
<_GLOBAL_OFFSET_TABLE_+0xb0>
400d16: 68 13 00 00 00 pushq $0x13
400d1b: e9 b0 fe ff ff jmpq 400bd0 <_init+0x20>


(so much for C++ function calls' not having extra run-time cost as compared to C
ones -- probably true only if you use nothrow functions throughout?)

As for the original purpose of the exercise, ostreamOutput() takes more than
thrice the code size of the printfOutput(). Judge for yourself.

STANDARD DISCLAIMER : your mileage can vary (not too much though :) ).


-Pavel

// -------------- pvocs.cpp -- cut here -------------------
#include <iomanip>
#include <iostream>
#include <sstream>
#include <stdio.h>

using namespace std;

void
printfOutput(size_t b, void *bAddress, int bEnabled, int bCore) {
char core[16];
if (bCore == -1) {
snprintf(core, sizeof(core), "%s", "All");
} else {
snprintf(core, sizeof(core), "%2.2d", bCore);
}
printf(" %2.2zu %016llx %3.3s %s\n", b, (long long)bAddress, core,
bEnabled ? "Yes" : "No");
}

void
ostreamOutput(size_t b, void *bAddress, int bEnabled, int bCore) {
ostringstream core;
bCore == -1 ? core << "All" : core << setw(3) << bCore;
clog << setfill(' ') << setw(3) << ' ' // indent
<< setfill('0') << setw(2) << b
<< setfill(' ') << setw(8) << ' '
<< setfill('0') << setw(16)
<< hex << reinterpret_cast<unsigned long>(bAddress)
<< setfill(' ') << setw(2) << ' '
<< core.str().substr(0, 3) << ' '
<< setfill(' ') << setw(3) << ' '
<< (static_cast<bool>(bEnabled) ? "Yes" : "No")
<< '\n';
}

int
main(int, char*[]) {
size_t b = 2;
void *bAddress = &b;
int bEnabled = 0;
int bCore = -1;
printfOutput(b, bAddress, bEnabled, bCore);
ostreamOutput(b, bAddress, bEnabled, bCore);
return 0;
}
// -------------- pvocs.cpp -- cut here -------------------
 
P

Pavel

Juha said:
And the alternative is what, exactly?

Writing the functions for each separate type manually? Exactly how would this
be different from the template (other than the template avoiding code
repetition)?

Making the same code support different types? And how exactly would this be
achieved? I see only two possibilities:

1) OO polymorphism, which isn't possible without RTTI (which was also banned
in that list) and would actually increase memory consumption by a significant
lot (because now objects would need to be heap-allocated).

2) Bypass type safety mechanisms and make the code handle things like void
pointers and such. Yeah, great solution. (Not only is it completely horrible
and unsafe code,
Just a friendly poke, please don't take too seriously: I hope you are writing
this post using an operating system unknown to me that is at least a decade old
but is not fully composed of such completely horrible and unsafe code...

More seriously, in my experience template code carries more bugs and uglier than
plain-old C-like code. I found it to be related to its inherent inflexibility
that manifests itself after a while, e.g. as follows:

1. At one moment in time we decide to use compile-time parametrization for a new
system. We assume the arguments will always be known at compile time. We build
the system and boast how flexible it is (e.g. how fast it is for us to plug in a
new algorithm or type) and higher management grows to rely on our ability to
deliver new functionality in a matter of few days, sometimes hours.

2. Sooner or later at least one "disruptive requirement" comes that translates
to a necessity to select an algo or type based on information only available at
run time. The "correct" approach would be to re-design a system and try to
provide "best of two worlds" but delivery would take months (with the resulting
system being notably more complex than the current one, but maintainable).
Higher management does not see any principal difference between the new
requirement and previous ones we aced so brilliantly; thus we are not getting
budget for redesign. Instead, we either instantiate code with all possible
combinations of template parameters (code bloating in its best) and select the
right one using some ugly variety of Factory or add some really dirty hack or two.

3. If the system is good for anything, that one disruptive requirement is
followed by a number of others, not necessarily disruptive in themselves, but
now they need to be implemented on top of over-bloated and/or ugly hacked
system. The bug frequency and code bloating starts increasing quadratically or
worse with the system size (whereas before the "disruptive requirement" we
managed to keep it almost linear). Everyone gets annoyed. If an original
designer did not leave the organization at stage #2, s/he leaves it now.

4. A 1-year-ago "beautiful little system" is now known as "an ugly
unmaintainable monster that devours thousands of top-consultant-hours per year
which we have to tolerate to stay in business". At this point, no one even dares
to request a performance improvement (the best answer of a swamped development
manager who "did not write this system" would be "buy better hardware; if you
are lucky we will be able to migrate to it in a couple of months"). Technically
speaking, running those glue-code-hacks (e.g. Factories) may now take more
run-time than using the resulting "products". Oh, yes, and compiling our system
now takes many hours on the best available hardware (maybe as long as it used to
take to add a new feature at stage #1).

I hate to say it but the initial decision to rely on compile-time
parametrization played a significant role in this outcome.

To summarize, I do not mind templates for "programming-in-small" but it would be
very unusual for me to base a design of a business system on them. Wherever
possible I am trying to give a non-trivial component a non-template interface
regardless of whether it uses templates in its implementation.

HTH
-Pavel


it also cannot handle everything that a template can, and
 
P

Pavel

Ian said:
Luca Risolia said:
On 13/05/2012 23:39, jacob navia wrote:
Le 13/05/12 20:33, Luca Risolia a écrit :
All that stuff can be written in a more readable, type-safe code by
using std::clog (or whatever stream you need) and standard manipulators.

Great!

Go ahead, and show us how.

if (p_num_breakpoints> 0) {
clog<< "Breakpoint Address Core Enabled?\n"
"---------- ---------------- ---- --------\n";

for (size_t b = 0; b< p_num_breakpoints; b++) {
const s_breakpoint *bpp =&p_breakpoints;
ostringstream core;
bpp->b_core == -1 ? core<< "All" : core<< setw(3)<< bpp->b_core;
clog<< setfill(' ')<< setw(3)<< ' ' // indent
<< setfill('0')<< setw(2)<< b
<< setfill(' ')<< setw(8)<< ''
<< setfill('0')<< setw(16)
<< hex<< reinterpret_cast<unsigned long>(bpp->b_address)
<< setfill(' ')<< setw(2)<< ''
<< core.str().substr(0, 3)<< ''
<< setfill(' ')<< setw(3)<< ''
<< boolalpha<< static_cast<bool>(bpp->b_enabled)
<< '\n';
}
}


More readable is certainly a matter of opinion, in this case.

if (bpp->b_core == -1) {
snprintf(core, sizeof(core), "%s", "All");
} else {
snprintf(core, sizeof(core), "%2.2d", bpp->b_core);
}
lp->log(" %2.2zu %016llx %3.3s %s\n",
b, bpp->b_address, core, bpp->b_enabled?"Yes":"No");

This is much more readable, and much more important to me, it will perform
much better than the C++ stuff you've written above (two function calls
versus many function calls, smaller cache footprint vs. larger cache footprint).


It will also fail in amusing ways in a 32 bit build.
All the C++ I write is in operating systems, hypervisors and other bare-metal
code for which performance is priority #1, and where we don't have the standard
C++ runtime (such as it is) available. No rtti, no exceptions, no templates
and very few reference objects.

Not that old FUD again. The only feature there that may impact performance is
RTTI. If anything, the reset will improve performance on any decent modern
compiler. Please, move on from the 90s.

Ian, with all due respect exceptions do matter -- please see my example above
for the difference between the epilogue code of printf- and ostream- using
output functions.

My post has all necessary data for you to experiment on your own and it is with
your modern enough g++ 4.6.3, optimized for code size.

-Pavel
 
P

Pavel

Ian said:
I'd like to see an example where exceptions slow things down. The first compiler
I did a comparative benchmark with was gcc 2.95 and I've yet to see a case where
an exception base solution was slower.


Me to. Maybe you were using them inappropriately (the example with lists
indicates you might). A template solution often enables the compiler to inline
calls, improving the icache footprint.
In general, it may -- but not for C++ streams that is the original subject of
this thread. C++ streams require virtual calls for conversions by the Standard.

-Pavel
 
I

Ian Collins

Ian, with all due respect exceptions do matter -- please see my example above
for the difference between the epilogue code of printf- and ostream- using
output functions.

iostreams aren't an example of comparing an exception based solution
with a call and test solution. Try a more apples to apples comparison
and exceptions will win the day.
 
I

Ian Collins

In general, it may -- but not for C++ streams that is the original subject of
this thread. C++ streams require virtual calls for conversions by the Standard.

My comment was in response to the claim templates negatively impact
performance, which is nonsense. Templates were introduced into the
thread as one place where iostreams really have to be used in preference
to C stream functions.
 
J

Juha Nieminen

Pavel said:
Instead, we either instantiate code with all possible
combinations of template parameters (code bloating in its best)

Ok, I have decided to not take seriously anybody who uses the term
"code bloat" to describe templates. It's just a myth that people keep
repeating like parrots, with little actual evidence.

(And by that I don't mean that using templates wouldn't increase the
size of the executable in any way. What I do mean is the implication
that templates cause the executable size to explode (which is what I
understand by "code bloat") and that there would be a better (or at
least equally good) alternative that does not cause an equivalent
increase in executable size, while still keeping the design of the
program equally clean, efficient and safe.)

Ironically, in some cases using templates can actually *reduce* the
size of the executable (because it allows the compiler to inline and
optimize the code on a type-by-type basis which, especially when dealing
with basic integral types and such, can help it eliminiate tons of code
that it would not be able to eliminate otherwise, had a more "C-like"
solution been used).
 
M

Martin B.

Not to blame templates in general for code bloating (bloating
compilation time is another story; for whatever reason no one here
complains about this one), but the above ostream code (and any iostream
code, in my experience) certainly bloats the code at the call site as
compared to printf code (...)

I composed two roughly equivalent printing
functions from the above example into a little program (see below),
compiled it with g++ 4.6.3 on 64-bit Linux, optimizing for size:

g++ -Os -o pvocs pvocs.cpp

and measured the functions from 'objdump -d' dump.

the size of printfOutput() is 0x400f22 - 0x400e74 + 1 = 175 bytes
the size of ostreamOutput() is x401146 - 0x400f23 + 5 = 552 bytes
(...)

(so much for C++ function calls' not having extra run-time cost as
compared to C ones -- probably true only if you use nothrow functions
throughout?)

As for the original purpose of the exercise, ostreamOutput() takes more
than thrice the code size of the printfOutput(). Judge for yourself.

STANDARD DISCLAIMER : your mileage can vary (not too much though :) ).

Are you trying to make a point wrt. templates, or wrt. the original
topic else-thread?

cheers,
Martin
 
M

Martin B.

Just a friendly poke, please don't take too seriously: I hope you are
writing this post using an operating system unknown to me that is at
least a decade old but is not fully composed of such completely horrible
and unsafe code...

Makes me wonder ... according to [The Programming Languages
Beacon](http://www.lextrait.com/vincent/implementations.html) MS Windows
uses C++ (whatever that means, it's not like we have too many details
here). That means we cannot rule out that some OS components are
actually using templates.
More seriously, in my experience template code carries more bugs and
uglier than plain-old C-like code. I found it to be related to its
inherent inflexibility that manifests itself after a while, e.g. as
follows:

Well, my (limited) experience is the opposite.
1. At one moment in time we decide to use compile-time parametrization
for a new system. We assume the arguments will always be known at
compile time. We build the system and boast how flexible (...)

2. Sooner or later at least one "disruptive requirement" comes that
translates to a necessity to select an algo or type based on information
only available at run time. (...)

3. If the system is good for anything, that one disruptive requirement
is followed by a number of others, not necessarily disruptive in
themselves, but now they need to be implemented on top of over-bloated
and/or ugly hacked system. (...)

4. A 1-year-ago "beautiful little system" is now known as "an ugly
unmaintainable monster (...) Oh, yes, and compiling our system now takes
many hours on the best available hardware (maybe as long as it used to
take to add a new feature at stage #1).

I hate to say it but the initial decision to rely on compile-time
parametrization played a significant role in this outcome.

Is this FUD based on any actual experience or did you make it up on the
spot? (And do you really believe that templates played a *significant*
role?)

Just sayin' ... you *don't have to* base the whole design of something
on templates. You don't have to understand
[Boost.Spirit](http://boost-spirit.com/home/) to be using templates.

std::vector and friends is just fine, stick to the basics.
To summarize, I do not mind templates for "programming-in-small" but it
would be very unusual for me to base a design of a business system on
them. Wherever possible I am trying to give a non-trivial component a
non-template interface regardless of whether it uses templates in its
implementation.

To repeat, this does seem like a prudent approach, but this doesn't
imply to not use *any* templates in a big project, and your quote from
above:
in my experience template code carries more bugs and
uglier than plain-old C-like code.

now more sounds like "huh, templates aren't the solution for everything,
you know", which I think noone really claims.

cheers,
Martin
 
M

Martin Shobe

Pavel said:
Martin said:
Luca Risolia wrote: [snip]
if (p_num_breakpoints> 0) {
clog<< "Breakpoint Address Core Enabled?\n"
"---------- ---------------- ---- --------\n";

for (size_t b = 0; b< p_num_breakpoints; b++) {
const s_breakpoint *bpp =&p_breakpoints;
ostringstream core;
bpp->b_core == -1 ? core<< "All" : core<< setw(3)<< bpp->b_core;

So, what's the advantage of this code, which is longer, more complex (counted,
for example, as the number of tokens even when adjusted with the number of
format specifiers from printf code) and unnecessary dynamic memory
[de]allocations dynamic inside the loop (which may start having quite
interesting performance implications for a process compiled with thread-safety
options somewhere in the middle of production) over the original code does not
do any of it?

Also, the output statement does not relate intuitively to the header so counting
all these setw arguments would make me feel dumb (for doing a stupid job that I
could have avoided if I used the right tools).


[snip]

Pavel, if the only thing you are responding to is the quoted part of the
post, you might want to consider replying to the quoted post instead.
This makes it look like you are asking me, and I didn't write this
code, and wouldn't write it that way. (I did post code showing how I
would do it, so if you have any question about that, feel free).

Martin Shobe
 
D

Dombo

Op 17-May-12 18:01, Scott Lurndal schreef:
Our definition of bloat obviously differs. For the code that I
work with, every single byte matters. The fact that templatization of
basic data structures will repeat the same code multiple types (once for
each parameterized type), is bloat.

That is not necessarily true. Instantiation of a template with another
parameterized type does not always result in code being generated
specifically for that type. The compiler/linker may reuse code generated
for another template instantiation. In case of Visual C++ I have seen
exactly that (by stepping through the generated assembly code).

Earlier you mentioned a double linked list with void* which requires the
programmer to make sure to use the correct casts and that the right type
is inserted. With a recent version of Visual C++ (and I expect also
other modern C++ compilers) you might as well have used templates
because the code generated for dl_list<A*> is also called for
dl_list<C*>...etc. I.e. you get type safety a no cost said:
I'm not talking about doubling
the executable text region size (although I've seen significant percentage
increases), but every cache line matters for certain classes of programs.

True, but if template instantiations share the same (not repeated) code
there is no increase in executable size or cache misses.
As Pavel pointed out, safe is relative. Pointers and casting void *
are perfectly valid C++ and can be used safely.

There is a difference between perfectly valid code and safe code.

I'm interested in how you get the compiler to complain if you
accidentally pass a pointer of the wrong type to a function or variable
taking a void* and when a wrong cast from a void* is made.

Not related to safety but to productivity, I'm also interested in how
you get intellisense/code completion feature (or whatever it is called
in your IDE) to know which members are on the object the void* is
referencing.
They also can be
misused. C'est la vie. They are way more efficient in many cases.

I'm not saying the use templates never leads to an increase of the
executable size, but I get the impression you believe that each template
instantiation always increases the size of the executable. With modern
compilers/linkers this is not necessarily the case.
 
L

Luca Risolia

I don't. The programmers are expected to test every line of code before
it gets checked in, and at least one peer must review the code prior to
acceptance into the tree.

Yes type safety is helpful, if it can be done without extra footprint.

I think what Dombo was trying to say is something like this:

template <class T> class Vector {
T*v;
int sz;
public:
Vector();
Vector(int);
T& elem(int i) {
return v;
}
T& operator[](int i);
void swap(Vector&);
//...
};

template<> class Vector<void*> { // complete specialization
void** p;
//...
void*& operator[](int i);
};

// ALL the partial specializations can now share the same code:
template<class T> class Vector<T*> : private Vector<void*> {
public:
typedef Vector<void*> Base;
Vector : Base() {}
explicit Vector(int i) : Base(i) {}
T& elem(int i) { return static_cast<T*&>(Base::elem(i)); }
T*& operator[](int i) { return static_cast<T*&>(Base::eek:perator[](i)); }
}

which is a rather simple idea, if your compiler does not do that for
you. Everything will be expanded in-line and type safety will be preserved.

Where is the "extra footprint" there?

(The example has been taken from the C++ bible)
 
J

Jorgen Grahn

Ok, I have decided to not take seriously anybody who uses the term
"code bloat" to describe templates. It's just a myth that people keep
repeating like parrots, with little actual evidence.

Yes. I'm very tempted to start trying to refute claims from Pavel and
S.L. in this thread ... but then I do a reality check. Templates
(writing new ones, and especially using the standard library's
containers and algorithms) are one of the cornerstones of modern C++.

Put differently, if I want C, I know where to find it.

(I also note that this is a re-run of a discussion back in January.
See e.g. Message-ID: <[email protected]>.
Same people involved, and I bet the same outcome: no consensus.)

/Jorgen
 
M

Marc

Scott said:
Dombo said:
That is not necessarily true. Instantiation of a template with another
parameterized type does not always result in code being generated
specifically for that type. The compiler/linker may reuse code generated
for another template instantiation. In case of Visual C++ I have seen
exactly that (by stepping through the generated assembly code).
[...]
I've never used microsoft compilers (well there were those two device
drivers in the late 90's for 3.51, but that doesn't really count), so
I'd have to see if g++ on unix/linux supports this.

If you use the gold linker, look at the --icf option.
 
J

Juha Nieminen

Scott Lurndal said:
As Pavel pointed out, safe is relative. Pointers and casting void *
are perfectly valid C++ and can be used safely.

"Can be used safely" != "safe".
Use the inline keyword with the appropriate functions when you write
them.

Did you miss the "optimize the code on a type-by-type basis" part?
 
M

Martin B.

Martin B. said:
Juha Nieminen wrote:
Code footprint in the icache (and memory) is the primary reason for no
templates.

And the alternative is what, exactly?

Writing the functions for each separate type manually? Exactly how
would this
be different from the template (other than the template avoiding code
repetition)?

Making the same code support different types? And how exactly would
this be
achieved? I see only two possibilities:

(...)

2) Bypass type safety mechanisms and make the code handle things like
void
pointers and such. Yeah, great solution. (Not only is it completely
horrible
and unsafe code,
Just a friendly poke, please don't take too seriously: I hope you are
writing this post using an operating system unknown to me that is at
least a decade old but is not fully composed of such completely horrible
and unsafe code...

Makes me wonder ... according to [The Programming Languages
Beacon](http://www.lextrait.com/vincent/implementations.html) MS Windows
uses C++ (whatever that means, it's not like we have too many details
here). That means we cannot rule out that some OS components are
actually using templates.

As of NT 5.0 (Win2000), none of NT was written in C++. I haven't seen
the source code for successive releases, but I seriously doubt that they've
changed.

Well. That's more than 10 years!

Anyways, given how the MS compiler handles C and C++, my personaly guess
would be that they compile their kernel code with the C++ compiler mode
but write mostly "C" code. I may be totally wrong of course.
Even if there was C++ code in the kernel, they would be very
unlikely to use Templates.

What information is this statement based on?

cheers,
Martin
 
A

Adam Skutt

 3) I tried the cout stuff that was posted:
* snip*
It also took 61 function calls versus the 4 function calls in my snprintfversion,
including constructors and destructors for dynamic objects.  Given thatthe snprintf
implementation in GLIBC is quite efficient, and that my log function simply writes the
char array to a file using the write(2) system call, the cout stuff is pretty pathetic
at a 10 to 1 code size factor.

There were also a handful of bus-locked (atomic) instructions generated inline, which
can be a significant problem in certain hardware environments and operating system kernels.

It's also not the least bit comparable to what your alternative code
is doing. To dismiss it based on this analysis alone is either
suggests that you don't know what iostreams does out of the box, nor
how to change the default behavior. Regardless, this comparsion
doesn't pass anything resembling intellectual honesty, nor can it
ever, really.

Your argument is fundamentally fallacious because you're taking a tiny
minority of programs and pretending they are the general case. Yes, C+
+ iostreams will still have more overhead compared to C FILE I/O,
which has more overhead compared to OS-specific I/O. However, that
overhead gets you plenty of extra functionality, so it's not like the
cost is without benefit. Just because you don't need those features
and can't afford the overhead does not let you conclude "cout is
useless in real applications," and it will never let you do so.

Adam
 

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
473,776
Messages
2,569,603
Members
45,188
Latest member
Crypto TaxSoftware

Latest Threads

Top