GCC is re-implementing in C++ and C discarded

8

88888 Dihedral

(e-mail address removed)æ–¼ 2012å¹´8月23日星期四UTC+8下åˆ9時32分02秒寫é“:
Well, the IOS and ARM or BCM CPUS are not selling in the Wintel business
model.

The objective C can be pick up very fast by professional C / C++
programmers.
 
M

Malcolm McLean

בת×ריך ×™×•× ×©×‘×ª,25 ב×וגוסט 2012 10:06:48 UTC+1, מ×ת Jorgen Grahn:
On Wed, 2012-08-22, Malcolm McLean wrote:

If that is true, it should worry C programmers.

C++ really /is/ the "better C" in the sense that like C it


There are no other important languages in that area.
C++ is a superset of C (pedants, attack !!!). So if you write C rather than
C++ you've necessarily rejected C++. The only exception is when you're
developing for tiny embedded systems that don't come with a C++ compiler.

Why would you do that? Basically to make code more reusable, and to reduce
dependencies between source files. If my binary image library was in C++,
fr example, then a "binary image" would be an "object". Then the routines
would be member functions of the class. If you do a competent job then it does
mean that people can rewrite the image class to take packed images. But it
also means that someone look for, say, a distance transform can't just take
the code and drop in into his own program, without also pulling in an entire
binary image class that does the same thing as the one he already
has, but slightly differently.
 
M

Malcolm McLean

בת×ריך ×™×•× ×©×™×©×™, 24 ב×וגוסט 2012 10:15:49 UTC+1, מ×ת Nick Keighley:
this whole conversation strikes me as bizzare. A kind of level
confusion. It reminds of one of my collegues who came out with "C++ is
upwards compatible with C because it is implemented in C" and couldn't
see what was wrong with that statement.
The first C++ compilers spat out C code, which was then fed to the C
compiler. Any language can be implemented in any other. The colleague
had probably heard a garbled version of the first statement, and wasn't
aware of the second.
 
R

Rui Maciel

Malcolm said:
The first C++ compilers spat out C code, which was then fed to the C
compiler. Any language can be implemented in any other. The colleague
had probably heard a garbled version of the first statement, and wasn't
aware of the second.

If I'm not mistaken, that trick ceassed to work once exceptions were thrown
in the mix.


Rui Maciel
 
J

Johannes Bauer

C++ is a superset of C (pedants, attack !!!). So if you write C rather than
C++ you've necessarily rejected C++. The only exception is when you're
developing for tiny embedded systems that don't come with a C++ compiler.

This isn't mere pedanticism ("new" keyword, etc.), but the bare truth:
Some constructs which are necessary for embedded systems are just syntax
errors in C++, while they work perfectly in C.

Best regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
J

Johannes Bauer

I can understand the necessity of using C on an embedded system if C++
is not available there. However, if a C++ compiler is available, I can't
imagine what these "necessary constructs" could be.

Placing an interrupt vector table in ROM:

struct ivtlayout {
int vec1;
int vec2;
int vec3;
};

struct ivtlayout ivt = {
.vec1 = 1234,
};

int main() {
return 0;
}
If you're talking about something non-portable, is there anything
preventing a C++ compiler from providing support for a corresponding
non-portable construct?

No, definitely not. Non-portable C++ could definitely provide this. I am
just really not a big fan of non-portable dialects. Actually, I really
don't know why this wasn't included in c++0x.

Best regards,
Johannes


--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
J

Jens Gustedt

Am 25.08.2012 15:35, schrieb James Kuyper:
However, that was basically just a trick (and it took me a long time to
perfect it). As far as I know, everything that can be done using
portable C code can also be done by using (possibly different) C code
that also compiles as C++ code, with the same exact meaning in both
languages (exception: code like that which I described above, whose sole
purpose is to detect which language it was compiled in - by definition
such code must behave differently in order to behave correctly). Could
you give a counter-example?

The intersection of C and C++ has
- no decent initializers, you'd need designated initializers on the C
side and constructors for C++
- no decent temporaries (compound literals for C and constructors for C++)
- no consistent way of passing dynamically sizes multi-dimensional
arrays to functions
- no type puning (union's are standardized differently between the
two)
- no consistent model for function inlining

not very attractive, at least for me

Jens
 
J

Johannes Bauer

The intersection of C and C++ has
- no decent initializers, you'd need designated initializers on the C
side and constructors for C++
- no decent temporaries (compound literals for C and constructors for C++)
- no consistent way of passing dynamically sizes multi-dimensional
arrays to functions
- no type puning (union's are standardized differently between the
two)
- no consistent model for function inlining

not very attractive, at least for me

I'm using C++ (and c++0x at that) for doing very, very low-level work,
down to 8 bit microcontrollers. And while most people seem to think that
this is impossible, quite the contrary is true: There is a huge benefit
in using it (if it is used correctly). For 8 bitters, for example, I do
not use fancy stuff (virtual methods, inheritance etc), nor parts of the
STL. I use heavily low-level language guarantees, such as strong typing
and especially strongly types class enums (gotta love those!).

To give an example on how MCU code looks using C and how it's usually
done (this is an example from an actual project of mine):

TCCR1A = _BV(COM1A1); /* Clear on Compare Match */
TCCR1B = _BV(CS10) | _BV(WGM13); /* 1 / 1 */
TCCR0B = _BV(CS02) | _BV(CS00);

where the _BV() macro is defined to be _BV(x) (1 << (x)). All the
symbols are defined by the standard library, the lvalues are volatile
registers and the rvalues are basically just bit definitions of the
hardware's datasheet.

This is just horrible. Notice how the settings of two different timers
are set, the first two lines refer to Timer 1 while the third refers to
timer 0. Both have a prescaler, or clock selection. Notice that the bits
in the standard library for this AVR processor are named CSnm, where n
is the timer (0, 1) and m is the bitvalue (0, 1, 2, 3). Obviously it is
*very* error-prone, because setting the wrong one in either register
leads to weird (and hard to debug results).

In C++, whith smart constructs, you can basically say

TCCR1().PRESCALER() = T1Presc::CKDIV_2;
TCCR0().PRESCALER() = T0Presc::CKDIV_16;

and it will boil down to the *exact* same code with no performance
penalty at all, only added typesafety. The compiler will barf if you try
to put the wrong type into a field. I find that quite awesome and this
is actually a reason for me to prefer C++ over C for this type of work.

Best regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
L

Les Cargill

Johannes said:
You clearly do *not* write low-level code.

Pre-initialized structures, which C provides, are for some architectures
I'm working in a *MUST*, since they determine the interrupt vector table
which gets transferred to C. C++ just does not offer this. Referring to
the Cortex-M3 and -M4 series here, for example (where the initial stack
pointer and the IVT are placed in the start of flash).

I am fairly sure it is eminently possible to use pre-initialized structs
in C++.
 
L

Les Cargill

Johannes said:
Could you give an example or three?

As I said in the previous postings, a construct like this is one of the
last reasons to have some files in C for MCU projects that I'm working
on. Omitting some deatils (like attribute specifiers which specify where
the IVT goes), but that's the gist:

struct ivtlayout {
int vec1;
int vec2;
int vec3;
};

struct ivtlayout ivt = {
.vec1 = 1234,
};

int main() {
return 0;
}


[~/tmp]: gcc -O2 -Wall -Wextra -std=c99 -pedantic x.c
[~/tmp]: g++ -O2 -Wall -Wextra -std=c++0x -pedantic x.c
x.c:8:2: Error: expected primary-expression before ».« token

Best regards,
Johannes


This seems to work. I commented out the string
".vec1 = 1234", which isn't strictly necessary anyway
( but is a nice thing to have available ).

C:\c\usenet>cat prein.cpp

#include <stdio.h>


struct ivtlayout {
int vec1;
int vec2;
int vec3;
};

struct ivtlayout ivt = {
/*.vec1 =*/ 1234,
};

int main() {
printf("ivt.vec1=%d\n",ivt.vec1);
return 0;
}

C:\c\usenet>g++ prein.cpp

C:\c\usenet>a
ivt.vec1=1234

C:\c\usenet>
 
J

James Kuyper

Placing an interrupt vector table in ROM:

struct ivtlayout {
int vec1;
int vec2;
int vec3;
};

struct ivtlayout ivt = {
.vec1 = 1234,
};

int main() {
return 0;
}


No, definitely not. Non-portable C++ could definitely provide this. I am
just really not a big fan of non-portable dialects. Actually, I really
don't know why this wasn't included in c++0x.

Neither C nor C++ provides a portable way of telling the compiler to put
any particular object in ROM (though giving a const-qualified object
static storage duration certainly permits something to be placed in ROM
- and that's equally true in both languages).

If the above code is guaranteed to place anything in ROM (presumably
ivt, though that would be easier to understand if it were declared
const), that guarantee is provided by the C compiler, not the C
standard. I know of no reason why a C++ compiler couldn't make the same
guarantee for exactly the same code. If a C++ compiler were targeted to
the same platform and the same audience, I'd actually expect it to make
the same guarantee.
 
K

Keith Thompson

Johannes Bauer said:
Placing an interrupt vector table in ROM:

struct ivtlayout {
int vec1;
int vec2;
int vec3;
};

struct ivtlayout ivt = {
.vec1 = 1234,
};

int main() {
return 0;
}

In this particular case, you could just write:

struct ivtlayout ivt = { 1234 };

More generally, you just need to specify the member values in the order
in which they're defined.

Designated initializers are admittedly more convenient, especially when
you don't want to (or can't) make assumptions about member order.

No, definitely not. Non-portable C++ could definitely provide this. I am
just really not a big fan of non-portable dialects. Actually, I really
don't know why this wasn't included in c++0x.

It's C++11 now. The 2011 ISO C++ standard did add a number
of features from C99, including long long, but it didn't add
designated initializers. I also don't know why they aren't in C++11
(I just checked the standard expecting to find them). VLAs and the
`restrict` keyword were also left out of C++11.
 
K

Keith Thompson

Johannes Bauer said:
struct ivtlayout {
int vec1;
int vec2;
int vec3;
};

struct ivtlayout ivt = {
.vec1 = 1234,
};

int main() {
return 0;
}


[~/tmp]: gcc -O2 -Wall -Wextra -std=c99 -pedantic x.c
[~/tmp]: g++ -O2 -Wall -Wextra -std=c++0x -pedantic x.c
x.c:8:2: Error: expected primary-expression before ».« token

At least newer versions of g++ (I have 4.7.0) give better error
messages:

c.cpp:7:24: warning: ISO C++ does not allow C99 designated initializers [-pedantic]
c.cpp:9:1: warning: missing initializer for member ‘ivtlayout::vec2’ [-Wmissing-field-initializers]
c.cpp:9:1: warning: missing initializer for member ‘ivtlayout::vec3’ [-Wmissing-field-initializers]

And "-std=c++11" is now an alias for "-std=c++0x" (or vice versa).
 
J

Johannes Bauer

I am fairly sure it is eminently possible to use pre-initialized structs
in C++.

Please refer to this discussion a year back about exactly that issue
(the thread was called "C vs. C++: non-trivial designated initializers
not supported"):

https://groups.google.com/forum/?hl=en&fromgroups=#!topic/comp.lang.c++/HeWVpymftTg

Best regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
J

Johannes Bauer

Neither C nor C++ provides a portable way of telling the compiler to put
any particular object in ROM (though giving a const-qualified object
static storage duration certainly permits something to be placed in ROM
- and that's equally true in both languages).

No, obviously not. I just need the language to be able to place a struct
somewhere, I'll handle the rest (actually, the linker will).
If the above code is guaranteed to place anything in ROM (presumably
ivt, though that would be easier to understand if it were declared
const), that guarantee is provided by the C compiler, not the C
standard. I know of no reason why a C++ compiler couldn't make the same
guarantee for exactly the same code. If a C++ compiler were targeted to
the same platform and the same audience, I'd actually expect it to make
the same guarantee.

The guarantee I need is that I can initialize elements in arbitrary
order (using designated initializers). That's all. The rest is linker
magic. C does that, C++ does not.

Best regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
K

Keith Thompson

Malcolm McLean said:
בת×ריך ×™×•× ×©×™×©×™, 24 ב×וגוסט 2012 10:15:49 UTC+1, מ×ת Nick Keighley:
The first C++ compilers spat out C code, which was then fed to the C
compiler. Any language can be implemented in any other. The colleague
had probably heard a garbled version of the first statement, and wasn't
aware of the second.

Even so, the existence of a C++ implementation that generates C code
doesn't imply anything about upwards compatibility. A C program
that uses `new` as an identifier is still an invalid C++ program.

I think it's sufficient to say that the colleage was wrong (on multiple
levels).
 
J

Johannes Bauer

In this particular case, you could just write:

struct ivtlayout ivt = { 1234 };

More generally, you just need to specify the member values in the order
in which they're defined.

*sigh* Obviously, yes. But that's not the point. The point is being able
to tell what vectors you want to use and not need to search through a
list of 98 vectors and hit the correct array position (which is, quite
frankly, incredibly inconvenient).
Designated initializers are admittedly more convenient, especially when
you don't want to (or can't) make assumptions about member order.

That is exactly the case here. There's a definition file in which all
almost 100 IRQ vectors are specified and you want to be able to say: "I
will use IRQs for DMA0 and for USART2". You don't want to look it up
somewhere and modify the 48th and 82th entry in a struct.
It's C++11 now. The 2011 ISO C++ standard did add a number
of features from C99, including long long, but it didn't add
designated initializers. I also don't know why they aren't in C++11
(I just checked the standard expecting to find them). VLAs and the
`restrict` keyword were also left out of C++11.

Ah, yes, I still write 0x all the time. Maybe in the next revision
they'll be in.

Best regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
J

Johannes Bauer

This seems to work. I commented out the string
".vec1 = 1234", which isn't strictly necessary anyway
( but is a nice thing to have available ).

Yes, when you comment out the whole point of the example, it works.

Best regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
L

Les Cargill

James said:
Neither C nor C++ provides a portable way of telling the compiler to put
any particular object in ROM (though giving a const-qualified object
static storage duration certainly permits something to be placed in ROM
- and that's equally true in both languages).

While that has been true for some toolchains, it's kind of not true any
more. There are .DATA , .TEXT and .BSS. The default is to put them into
RAM. If you write your own linker scripts, then you can
do what you like.
(yes, there's also the heap and the stack... )

For additional partitions, you have to use ... pragmas are other domain
dependent extensions.
If the above code is guaranteed to place anything in ROM (presumably
ivt, though that would be easier to understand if it were declared
const), that guarantee is provided by the C compiler, not the C
standard. I know of no reason why a C++ compiler couldn't make the same
guarantee for exactly the same code. If a C++ compiler were targeted to
the same platform and the same audience, I'd actually expect it to make
the same guarantee.


If it works in 'C' the chances are excellent that it will work in C++.
The problem he had above was the construct ".vec1 = 1234," - the
".vec1 = " part is not recognized in C++. C++ forces you to declare
const memory layouts in order.
 
J

James Kuyper

Am 25.08.2012 15:35, schrieb James Kuyper:

The intersection of C and C++ has
- no decent initializers, you'd need designated initializers on the C
side and constructors for C++

???
The claim was that use of C was a necessity, not just a convenience. C
doesn't have constructors, and designated initializers are only a
convenience feature that don't do anything that can't already be done
using ordinary initializers - they just make it more convenient.
- no decent temporaries (compound literals for C and constructors for C++)

???
A compound literal doesn't do any thing that can't be done with an
explicitly declared and named temporary object. Again, it's just a
convenience feature.
- no consistent way of passing dynamically sizes multi-dimensional
arrays to functions

???
int func (double *array, rows, cols)
{
// to access column c of row r:
array[r*cols + c]

VLAs are also just a convenience feature - the don't do anything that
can't be done less conveniently by other methods.

It might just be jealousy on my part - I've never been paid to program
in an environment where I was permitted to use either designated
initializers or VLAs; I've regretted having to work within those
restrictions, but never had any trouble working around them, so the
claim that a lack of support for those features renders C++ unusable
strikes me as quite laughable.
- no type puning (union's are standardized differently between the
two)

Could you explain the relevant differences? There are things prohibited
in C++ unions that aren't even meaningful in C unions, but I'm not aware
of anything that C unions allow you to do that couldn't also be done in
C++. I'm willing to believe that I might have missed something, but you
need to be more specific.
- no consistent model for function inlining

There are significant subtle differences between the two languages with
respect to inlining. However, the supposed "necessity" of programming in
C as a result of those differences would be much clearer with a
sufficiently specific example.
 

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,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top