Thursday, March 3, 2016

Digest for comp.lang.c++@googlegroups.com - 25 updates in 8 topics

Juha Nieminen <nospam@thanks.invalid>: Mar 03 02:40PM

> I believe that the major usage of C nowadays is embedded software such as EMS (engine management systems) where dynamic allocation of
> memory is strictly forbidden. C++ will probably never be used in such environments.
 
You seem to be implying that it's impossible to write a C++ program
without dynamic memory allocation.
 
Is there an *actual* reason why C++ is forbidden, rather than a
completely false made-up one?
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
Juha Nieminen <nospam@thanks.invalid>: Mar 03 02:43PM

>>I believe that the major usage of C nowadays is embedded software such
 
> I thought the major use of C nowadays was on the linux kernel because
> linus got a stick up his ass about C++.
 
Yeah. His argument against using C and abhorring C++ is, essentially,
that C automatically leads to good and efficient code, while C++
automatically leads to very inefficient and problematic code.
Because reasons. (Also, he still seems to live in the early 90's
in terms of what he knows about C++.)
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
SG <s.gesemann@gmail.com>: Mar 03 07:46AM -0800

On Wednesday, March 2, 2016 at 6:39:15 PM UTC+1, Christopher Pisz wrote:
 
> I wish we could just have C++ without C. So, many problems come from C.
> So many developers that would use C++ if not for the messes C made.
 
Have you tried Rust yet? To me it feels like a cleaned up, simplified
C++ that shares many of its goals (e.g. zero overhead principle). It
strives for better type-, memory- and thread-safety and already offers
features the C++ standardization committee/community is currently
working on (like modular checking of generics, convenient ways of
destructuring/matching tuples and other kinds of values, or something
like an overloadable dot operator for "smart proxies").
 
Cheers!
sg
David Brown <david.brown@hesbynett.no>: Mar 03 04:46PM +0100

On 03/03/16 15:40, Juha Nieminen wrote:
> without dynamic memory allocation.
 
> Is there an *actual* reason why C++ is forbidden, rather than a
> completely false made-up one?
 
There are actual reasons why dynamic memory is often forbidden in
embedded software (it makes it hard to reason about correctness, it is
hard to determine worst case timing, code can work fine in testing but
fail in practice due to heap fragmentation, and if memory runs out then
an embedded system typically cannot just print a nice error message and
exit).
 
There are no requirements in C++ to use dynamic memory, though it is
often used "behind the scenes" - you have to be careful and know what
you are doing if you want to avoid dynamic memory entirely. Of course,
you have to be careful and know what you are doing if you want to write
good, correct embedded software anyway.
 
There are lots of reasons why many people object to using C++ in
embedded systems, and prefer, recommend or require plain C. But there
are also lots of reasons why C++ is a better choice than plain C. Some
of the reasons used to argue either way are in fact reasonable and
applicable to modern microcontrollers, modern tools, modern programmers
and modern projects - but many (especially those arguing against C++)
are based on outdated issues or myths.
 
In real-world practice, C++ is on the increase in embedded development.
scott@slp53.sl.home (Scott Lurndal): Mar 03 04:14PM


>> What do you do when your embedded program runs out of ram? Does the car crash?
 
>Most smaller embedded applications (whether C or C++) don't use dynamic
>allocation.
 
I've written parts of two major operating systems and a distributed hypervisor
all written in C++.
 
Like any useful language, allocation is up to the programmer, not the
language. Using placement new or ::new operators with memory pool objects
works just fine when memory is constrained. No heap necessary. STL generally
not useful. Exceptions disabled. RTTI disabled.
scott@slp53.sl.home (Scott Lurndal): Mar 03 04:17PM


>Plenty of people are doing device drivers, operating system components
>(or even entire operating systems) and embedded applications in C++.
 
>20 years ago an entire operating system (BeOS) was written in C++.
 
25 years ago, the Chorus systemes microkernel, the Unisys OPUS operating system
and the European Amadeus distributed operating system were all written
in C++ or a mix of C++ and legacy C driver code.
Wouter van Ooijen <wouter@voti.nl>: Mar 03 05:18PM +0100

Op 03-Mar-16 om 4:46 PM schreef David Brown:
 
> There are no requirements in C++ to use dynamic memory, though it is
> often used "behind the scenes" - you have to be careful and know what
> you are doing if you want to avoid dynamic memory entirely.
 
Luckily its is fairly easy to check (as opposed to being certain
upfront, which would of course be better): link with a missing
implementation of free().
 
Actually, I link with
 
#include <stdlib.h>
 
// using malloc must cause a linker error
void * malloc( size_t n ){
void if_you_see_this_you_are_using_new_or_malloc();
if_you_see_this_you_are_using_new_or_malloc();
return NULL;
}
 
// using free must cause a linker error
void free( void * p ){
void if_you_see_this_you_are_using_free_or_delete();
if_you_see_this_you_are_using_free_or_delete();
}
 
> (snip)
> In real-world practice, C++ is on the increase in embedded development.
 
Are there any sites, lists, congresses, publications, etc. dedicated to
exeactly this (C++ on embedded systems, especially realy small
micro-controllers)? It is my favourite subject, but I have a hard time
finding people and ideas in this direction.
 
"objects no thanks" Wouter van Ooijen
Juha Nieminen <nospam@thanks.invalid>: Mar 03 02:35PM

> Unlike std::string, a std::vector can't use the short buffer
> optimization
 
Why not? I don't think there's anything in the specification of
std::vector to stop it from doing that.
 
The boost small_vector is, in fact, exactly this. (I haven't checked
if it's 100% std::vector-compliant in terms of the C++ standard, but
I don't see why it couldn't be.)
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Mar 03 03:53PM +0100

On 03.03.2016 15:35, Juha Nieminen wrote:
>> optimization
 
> Why not? I don't think there's anything in the specification of
> std::vector to stop it from doing that.
 
You can swap two std::vector instances and keep item references valid.
 
That's only possible when it's the buffers themselves that are swapped.
 
The small buffer optimization is where storage in the vector object
itself is used as buffer: it can't be swapped around.
 
 
> The boost small_vector is, in fact, exactly this. (I haven't checked
> if it's 100% std::vector-compliant in terms of the C++ standard, but
> I don't see why it couldn't be.)
 
Presumably the Boost small vector doesn't claim to conform to the full
`std::vector` requirements. Thanks for pointing me in that direction! :)
I didn't know about it.
 
 
Cheers & hth.,
 
- Alf
Marcel Mueller <news.5.maazl@spamgourmet.org>: Feb 27 07:55PM +0100

Let's have a dispatch table of an assembler.
 
 
/// Entry of the OP code lookup table, POD, compatible with binary_search().
/// @tparam L maximum length of Name.
template <size_t L>
struct opEntry
{ char Name[L]; ///< OP code name
void (Parser::*Func)(int);///< Parser function to call, receives the
agrument below.
int Arg; ///< Arbitrary argument to the parser function.
};
 
/// Map with opcode tokens, must be ordered.
const Parser::opEntry<8> Parser::opcodeMap[] =
{ {"add", &Parser::assembleADD, Inst::A_ADD }
, {"and", &Parser::assembleADD, Inst::A_AND }
, {"asr", &Parser::assembleADD, Inst::A_ASR }
, {"bpkt", &Parser::assembleSIG, Inst::S_BREAK }
, {"bra", &Parser::assembleBRANCH, false }
//...
};
 
 
Each parser function takes an (optional) argument. The type is fixed to
int in this example. But this is not safe. Mostly the type is some enum.
But each function takes another argument type, and of course, the third
argument in the table must match the argument type of the function.
 
For type safe operation it would be nice to have a type like
 
 
template <size_t L, typename P>
struct opEntry
{ char Name[L]; ///< OP code name
void (Parser::*Func)(P);///< Parser function to call, receives the
agrument below.
P Arg; ///< Arbitrary argument to the parser function.
};
 
 
But this does not work since each line of Parser::opcodeMap[] has
another type P in general and all of these structures must fit into the
same storage. Of course, there is only a solution when sizeof(P) has an
upper limit, since this is similar to a union.
 
Could this be expressed type safe in C++11, without the need to deal
with pointers, new and delete for each line?
 
 
Marcel
Les Cargill <lcargill99@comcast.com>: Feb 25 12:05PM -0600

bitrex wrote:
> frac_low : 8;
 
> };
> } phase_accumulator;
 
 
If it doesn't, fix it. Endianness is more or less undefined behavior in
'C' so you have to test it.
 
Walk a 1 through phase_accumulator_full and print out ( or just store
the result and dump it with a JTAG if you are without a console ).
 
--
Les Cargill
David Brown <david.brown@hesbynett.no>: Feb 26 05:09PM +0100

On 25/02/16 19:05, Les Cargill wrote:
>> } phase_accumulator;
 
> If it doesn't, fix it. Endianness is more or less undefined behavior in
> 'C' so you have to test it.
 
No, endianness is not remotely "undefined behaviour" - it is
/implementation/ defined behaviour. There is a huge difference.
 
This means that the implementation has to document exactly what
endianness is used - and in the case of ARM compilers for embedded
systems, this is specified in the ARM EABI to be little endian.
 
Being implementation-defined behaviour, this also means that you /can/
test it - sometimes that is easier than trying to find the relevant
documentation! Once you have tested it, you know exactly how it works
for that implementation. And while in theory it could change in later
versions of the compiler, making such a change between compiler versions
would be astoundingly stupid and unhelpful - especially in an embedded
compiler - so it is not going to happen. (I know of only one case where
this happened - and that was on MS's x86 compiler, a long time ago,
where they changed the bitfield endianness.)
 
If endianness (or bitfield endianness) really were undefined behaviour,
you could not rely on it being the same between two runs of the same
compiler on the same source code - testing would be useless.
 
scott@slp53.sl.home (Scott Lurndal): Feb 26 05:29PM

>> 'C' so you have to test it.
 
>No, endianness is not remotely "undefined behaviour" - it is
>/implementation/ defined behaviour. There is a huge difference.
 
We have software that is built for both big-endian and little-endian
hosts (and more interestingly, it must internally simulate both big-endian
and little-endian processors).
 
We have this in one of the project header files.
 
#include <endian.h>
#ifndef __BYTE_ORDER
#if defined(__BIG_ENDIAN) && !defined(__LITTLE_ENDIAN)
#define __BYTE_ORDER __BIG_ENDIAN
#elif !defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN)
#define __BYTE_ORDER __LITTLE_ENDIAN
#define __BIG_ENDIAN 4321
#elif !defined(__BIG_ENDIAN) && !defined(__LITTLE_ENDIAN)
#define __BIG_ENDIAN 4321
#define __BYTE_ORDER __BIG_ENDIAN
#else
#error Unable to determine Endian mode

No comments: