A concern about mixing C and C++

J

jacob navia

Keith Thompson a écrit :
On the other hand, for any language at a higher level than assembler,
the compiler may find opportunities for optimizations that someone
creating hand-written assembler wouldn't find, or would choose not to
use.

For example, if I'm writing low-level code that I expect to be
maintained, I'm not likely to perform a pervasive optimization that
works only if an array size is a power of 2.

A skilled assembly language programmer is likely to be much smarter
than an optimizing compiler, but an optimizer has a different set of
tradeoffs to consider. A programmer will perform optimizations over
time as he's working on a piece of code; an optimizing compiler will
redo all its work from scratch every time it's invoked.

Yes, you can use an optimizing compiler as a way to generate assembly
language -- but that argument doesn't apply to hand-written assembly
language.

The things I had in mind is that templates expose to the
compiler details that allows more optimizations than what
an assembly language programmer would do. Specifically it would
be highly surprising that he/she writes the same optimized version
for a qsort search for each possible type of argument that the
function could receive. Most likely it will design a general
qsort interface (like C offers) that will be highly optimized
but never as optimized as a specially tailored qsort for each
input type.

jacob
 
A

Ark

Ian said:
typedef struct X {int x; const struct X *next;} X;

Is valid C but not C++.

typedef struct X {int x; const X *next;} X;

Is valid C++ but not C.

typedef struct X_t {int x; const struct X_t *next;} X;

Is valid C++ and C.


Correct , C++ prohibits uninitialised consts. Easily fixed for both thus:

extern const X x;
extern const X y;
const X z = {5, &x};
const X y = {6, &z};
const X x = {7, &y};


The C++ compiler pushed one extra register on the stack. The function
name does not make any difference.
1. It is not an easy fix if I want x, y, z to also be static. (Actually,
regardless of whether they are const).
2. It's interesting to understand /why/ C++ uses more stack. Is it, by
any chance, for passing (e.g. passing through) a pointer to an exception
object? In any event, those things get compounded... definitely a
consideration for resource-constrained environments...
- Ark
 
M

Malcolm

jacob navia said:
Keith Thompson a écrit :

The things I had in mind is that templates expose to the
compiler details that allows more optimizations than what
an assembly language programmer would do. Specifically it would
be highly surprising that he/she writes the same optimized version
for a qsort search for each possible type of argument that the
function could receive. Most likely it will design a general
qsort interface (like C offers) that will be highly optimized
but never as optimized as a specially tailored qsort for each
input type.
I did see some benchmarks for the standard template library, and they were
better than C equivalents. I thought that maybe the time had come to go to
C++.
What I forgot was that the syntax was difficult, and in fact a step too far,
with an already difficult and overloaded language. No one could use the STL
constructs effectively. So the experiment was short-lived, and now I have
virtually given up on C++ altogether.
 
S

Stephen Sprunk

ziman137 said:
I am currently working to implement an algorithmic library. Because
the performance is the most important factor in later applications,
I
decide to write it in C instead of C++. However, I thought it might
be
convenient to use some C++ code at some misc places. I'm aware
that, I could always use the C++ compiler to get it work.

There's two basic approaches to mixing C and C++:

1. Write the code in C and provide (optional) C++ wrappers.
2. Write the code in C++ and provide (optional) C wrappers.

Once you use _any_ C++isms in your library, you're forever chained to
the portability problems that C++ still encounters, limit yourself to
systems with C++ available, etc. Once you've paid that price, you
might as well write the whole library in C++ and then it's off-topic
for clc (though clc++ will probably be happy to help with the C
wrappers).
My intention for choosing C interface instead of C++ OOD is to gain
the
maximum performance as possible, yet I still like to use some C++
coding features (e.g., "const", reference instead of pointers, ...).

If you're going to write the library in the subset of C++ that looks
like C, you might as well write it in C and forgo the syntactic sugar
that C++ provides (except, perhaps, in some C++ wrappers). If you
can't give up C++'s syntactic sugar, then write the library in _real_
C++ (not some ugly common subset of the two) and provide C wrappers.

Mixing languages in the same project is considered bad form unless you
have a really strong reason, and "const" or "references" are IMHO not
a reason worth dealing with all the headaches of that "solution".

S
 
A

Al Balmer

I don't know if you do this, but I often find I can obtain more
productive optimisations by using the generated assembly language to
tune the high level language code rather than hand editing the assembly.

When you do that, are you not tuning your code to a particular
compiler? No worse than tuning the assembler code, of course, and less
detrimental to portability. For the ultimate in (non-portable)
efficiency, you might do another iteration of the process.
One area optimising compilers have an edge and will continue to improve
is global optimisations, there is only so much code a human can retain
in working memory. We can often do better with micro-optimisations, but
the compiler is better equipped to see the big picture.

Even if the programmer can see the big picture, the compiler can do it
systematically and much more quickly.
 
I

Ian Collins

Al said:
When you do that, are you not tuning your code to a particular
compiler? No worse than tuning the assembler code, of course, and less
detrimental to portability. For the ultimate in (non-portable)
efficiency, you might do another iteration of the process.
Like most low level optimisations, I tend to do this on embedded
systems, where portability isn't too much of an issue (I've found it
more cost effective to throw faster hardware at desktop applications
rather than fiddle with low level optimisations). The results can be
dramatic, one compiler I used generated diabolical code with loops like

for( i = 0; i < size; ++i )
{
doStuffWith( array );
}

But good tight code with

int* p = array;
int* end = array+size;

while( p != end )
{
doStuffWith( *p++ );
}
 
A

Al Balmer

Like most low level optimisations, I tend to do this on embedded
systems, where portability isn't too much of an issue (I've found it
more cost effective to throw faster hardware at desktop applications
rather than fiddle with low level optimisations). The results can be
dramatic, one compiler I used generated diabolical code with loops like

for( i = 0; i < size; ++i )
{
doStuffWith( array );
}

But good tight code with

int* p = array;
int* end = array+size;

while( p != end )
{
doStuffWith( *p++ );
}


I can believe it - I've seen some strange things. Sometimes compilers
used for embedded devices seem to assume that the user will tweak the
assembler :)

I don't do much embedded programming myself anymore, but the hardware
guy down the hall yells for help quite often, so I still see a lot of
it. We often sit in his office and massage C source until the
assembler looks the way he wants it.
 
F

Frederick Gotham

Ian Collins posted:
One compiler I used generated diabolical code with loops like

for( i = 0; i < size; ++i )
{
doStuffWith( array );
}

But good tight code with

int* p = array;
int* end = array+size;

while( p != end )
{
doStuffWith( *p++ );
}



If I know the the loop must execute at least once, then I choose:

T *p = array;

T const *const p_over = array + len;

do Process(*p++);
while(p_over != p);
 
D

Dave Thompson

Ark wrote:

typedef struct X {int x; const struct X *next;} X;

Is valid C but not C++.
Wrong. In C++ it is a 'benign' redefinition of the typename, which is
allowed. For essentially this reason.
typedef struct X {int x; const X *next;} X;

Is valid C++ but not C.

typedef struct X_t {int x; const struct X_t *next;} X;

Is valid C++ and C.
Both right.
Correct , C++ prohibits uninitialised consts. Easily fixed for both thus:
Even for nonconst C++ prohibits the declare-now define-later approach
without (explicit) extern, which as you note fixes the problem.
extern const X x;
extern const X y;
const X z = {5, &x};
const X y = {6, &z};
const X x = {7, &y};
However, this does not work for static=internal-linkage variables.
C++ does not allow /*qual?*/ static X x;
then /*qual*/ /*static*/ X x = init;

Or, write a ctor or other factory routine for X and:
const X z = X /* or makeX */ (5, &x);
etc.

For this particular case in EITHER C or C++
I might also consider something like:
const /*struct*/ X array [3] =
{ { 5, &array[2] }, { 6, &array[1] }, { 7, &array[0] } };
#define x array[2] // only if x is a more unique name
or in C++ X & x (&array[2])
etc.

- David.Thompson1 at worldnet.att.net
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top