Friday, March 4, 2016

Digest for comp.lang.c++@googlegroups.com - 16 updates in 3 topics

Ian Collins <ian-news@hotmail.com>: Mar 05 10:09AM +1300

On 03/05/16 03:02, Öö Tiib wrote:
> // ... do what you need
> return 0;
> }
 
That is basically the fiddle I came up with. The compiler errors are a
little obscure, but a comment fixes that. I added This:
 
constexpr int checkRange( int n ) {
(n < 1000) ? true : throw 0; return n; }
 
constexpr int f( int n ) { checkRange( n ); return n; }
 
It looks like the latest g++ has trouble spotting this in some
conditions, for example given these two lines:
 
constexpr int x {f(1000)};
char buf[f(8000)];
 
g++ >=5 spots the first as an error, but not the second. g++ 4.9 just
spits the dummy and runs.
 
Oracle CC spots them both:
 
Error: Initializer for constexpr variable x must be a constant expression.
Error: An integer constant expression is required within the array
subscript operator.
 
--
Ian Collins
"Öö Tiib" <ootiib@hot.ee>: Mar 04 02:39PM -0800

On Friday, 4 March 2016 23:09:40 UTC+2, Ian Collins wrote:
> little obscure, but a comment fixes that. I added This:
 
> constexpr int checkRange( int n ) {
> (n < 1000) ? true : throw 0; return n; }
 
More often people merge there like:

constexpr int checkRange( int n ) {return (n < 1000) ? n : throw 0;}
 
> char buf[f(8000)];
 
> g++ >=5 spots the first as an error, but not the second. g++ 4.9 just
> spits the dummy and runs.
 
The g++ has some sort of variable-length automatic arrays extension
so it somehow weasels out using that on second case I suspect.
 
 
> Error: Initializer for constexpr variable x must be a constant expression.
> Error: An integer constant expression is required within the array
> subscript operator.
 
Yes, compiler makers are humans too and sometimes mix up when it
is "ill-formed" so they have to diagnose and when it is "undefined
behavior" so they may screw us.
The constexpr is relatively new so we have to calmly fire the bugs
for some years.
Ian Collins <ian-news@hotmail.com>: Mar 05 11:55AM +1300

On 03/05/16 11:39, Öö Tiib wrote:
>> spits the dummy and runs.
 
> The g++ has some sort of variable-length automatic arrays extension
> so it somehow weasels out using that on second case I suspect.
 
Good spot, adding -pedantic (almost) does the trick:
 
warning: ISO C++ forbids variable length array 'buf' [-Wvla]
char buf[f(8000)];
 
So you would need both -pedantic and -Werror to catch this case.
 
--
Ian Collins
David Brown <david.brown@hesbynett.no>: Mar 04 06:58PM +0100

On 04/03/16 18:34, Richard wrote:
> question of how would you do things in practice under a constrained
> environment where using the heap is out of the question. Avoiding being
> "clever" here is probably the best advice.
 
On that last point, I agree entirely - being "clever" is rarely a good plan!
 
Without a heap, classes like vector would be of limited value. However,
I could see the use of a map or queue container of some sort (not
necessarily the standard library types) with either a fixed constant
maximum size, or perhaps with a fixed size given when the structure is
allocated on the stack (like a VLA).
 
>> that shared_ptr does [...]
 
> Again -- shared_ptr is for using the heap. Why would you be
> attempting to use shared_ptr when you don't want to use the heap?
 
The concept of "smart pointers" can be used for a variety of purposes,
not just to track memory. Whenever you have RAII to control a resource,
and you might want to access that resource from several contexts (like
different RTOS threads), you could have a shared pointer type of
management class. But in such cases, you would probably know in advance
exactly how many such managers you would want, and be able to have
statically allocated data (such as reference counters) for them - you
would perhaps want your own specialised sharer class, rather than a
shared_ptr.
 
There are also other types of dynamic memory that can be allowed in
embedded systems even if a general malloc-style heap is banned. In
systems with Ethernet, it is common to have dynamically allocated
buffers and other resources - but they would come from specific pools in
order to be sure that you have control over allocation/deallocation
times, avoid memory fragmentation, and do not end up with low-priority
processes using all the memory and leaving nothing for high-priority
situations. A standard smart_ptr may be a suitable way of handling such
buffers - but only if the pointer's control block can be allocated in a
controlled manner rather than on the heap.
 
Gareth Owen <gwowen@gmail.com>: Mar 04 06:02PM


> int foo[16];
> // fill in values
> std::sort(std::begin(foo), std::end(foo));
 
or, if you're just lazy...
 
int foo[16];
// fill in values
std::sort(foo,foo+16);
scott@slp53.sl.home (Scott Lurndal): Mar 04 06:30PM

>>to code footprint
>>issues (partially resolved in more modern compilers).
 
>Oh yeah, I remember Cfront on SGIs :-).
 
To be accurate, the cfront project was a Burroughs/Convergent Technologies -> Unisys
distributed operating system for a massively parallel system (called OPUS)
and development servers were motorola 88100 VME boxes (later Unisys S/8400
88100 boxes) using NCD-16 X-terminals. We were far more concerned with the
C compiler used to compile the output of cfront (it was a PCC port to M88100).
 
SGI had a real C++ compiler (and a pretty good one, too).
Juha Nieminen <nospam@thanks.invalid>: Mar 04 07:28PM

> Compiling the Linux kernel with some random perfectly-conforming
> C compiler will probably result in a kernel which doesn't actually work.
 
Given that the linux kernel (as most kernels) contains some inline asm,
it's not exactly 100% C-standard compliant in the first place...
 
(I don't think a kernel can be implemented with zero inline-asm, at
least not for the x86 architecture, assuming the kernel is 32-bit or
64-bit. At the very least you need code to perform a mode switch.)
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
Juha Nieminen <nospam@thanks.invalid>: Mar 04 07:35PM

> 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.
 
I'm not sure in which non-obvious situation a C++ program would use
dynamic memory allocation. I don't think even virtual functions (if
you wanted to use them for some strange reason) would cause dynamic
memory allocation. (AFAIK virtual tables are static, with at most their
pointers being set at launch time, if even then.)
 
Sure, if you use the standard containers, dynamic allocations will
be made, but that's a no-brainer. (Although there's a way to use them
without dynamic allocation, if you really need to. You simply have to
implement your own allocator for them, which uses a static buffer.)
 
I'd say there are many things in C that might or might not use
dynamic memory allocation, and it's hard to know for sure. For
example, does fopen() or fread() use dynamic memory allocation?
I have no idea. (I think that these may be needed even in small
embedded environments in some cases.)
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
David Brown <david.brown@hesbynett.no>: Mar 04 08:50PM +0100

On 04/03/16 20:35, Juha Nieminen wrote:
> example, does fopen() or fread() use dynamic memory allocation?
> I have no idea. (I think that these may be needed even in small
> embedded environments in some cases.)
 
I think you would rarely need such functions in an embedded system that
is too constrained (in resources or timing requirements) to have a heap.
But your point is perfectly valid - C functions may use heap memory
without making it clear, just like C++ functions or classes.
scott@slp53.sl.home (Scott Lurndal): Mar 04 08:04PM


>(I don't think a kernel can be implemented with zero inline-asm, at
>least not for the x86 architecture, assuming the kernel is 32-bit or
>64-bit. At the very least you need code to perform a mode switch.)
 
GCC already has various __builtin functions that can be used to
generate specific assembly (__builtin_popcount is one I use heavily).
Other high-level languages I've used for OS development implemented
similar intrinsic functions (e.g. ALGOL for Burroughs Large Systems,
SPRITE for Burroughs medium systems, SPL for HP-3000's, BLISS-32 on
Digital systems, et alia) to generate specific instructions.
 
Burroughs medium systems COBOL68 compiler had a statement called 'ENTER
SYMBOLIC' that allowed inline assembler in COBOL programs. There was
no assembler offered to customers with either of the Medium or Large
systems mainframe lines and COBOL74 removed the ability to ENTER SYMBOLIC.
scott@slp53.sl.home (Scott Lurndal): Mar 04 08:06PM

>example, does fopen() or fread() use dynamic memory allocation?
>I have no idea. (I think that these may be needed even in small
>embedded environments in some cases.)
 
In our C++ hypervisor, we did this:
 
/*
* This is called by setup64.S to call the constructors of global objects,
* before it calls dvmm_bsp_start().
*
* GNU LD lays out the __CTOR_LIST__ as an array of function pointers. The
* first element of the array (index == 0) contains an integer which
* represents the value derived from subtracting two from the actual number
* of entries in the table. Thus the content of the first element is
* one less than the index of the last entry in the table.
*
* Call in reverse order XXX - why? Check crt0.o for canonical behavior
*/
extern "C" void
__call_constructors()
{
size_t count = *(size_t *)__CTOR_LIST__;
 
for(count++; count; --count) {
__CTOR_LIST__[count]();
}
}
 
/*
* G++'s generated code calls this if a pure virtual member is ever called.
*/
extern "C" void
__cxa_pure_virtual()
{
panic("pure virtual function called\n");
}
 
/*
* This is needed even though we don't ever use the delete operator because
* G++ generates an extra (unused) virtual destructor that calls it.
*/
void
operator delete(void *)
{
panic("operator delete(void*) called\n");
}
 
/*
* Catch unintended calls to new.
*/
void*
operator new(size_t)
{
panic("operator new(void*) called\n");
}
Wouter van Ooijen <wouter@voti.nl>: Mar 04 09:27PM +0100

Op 04-Mar-16 om 6:31 PM schreef Richard:
 
> I'm talking about his point about avoiding dynamic memory allocation.
> Functors and exceptions don't have to do with dynamic memory
> allocation unless you start writing calls to new yourself.
 
IME that is not true. The exception handling 'framework' that is added
when you use exception does use the heap, as does std::function.
 
(snip)
 
>> requirement that sin() doesn't use the heap.
 
> Sorry, this is either a pointless exercise in pedantry or it is a
> straw man argument.
 
Why? The point is that without trying I can make an educated guess what
kind of library elements do or don't use any of (heap, exception, RTTI),
but I can't be sure.
 
Wouter
Ian Collins <ian-news@hotmail.com>: Mar 05 09:34AM +1300

On 03/05/16 04:41, Richard wrote:
 
> I assume you are referring to containers when you say "STL".
> I can't see why the algorithms wouldn't be useful in a constrained
> environment.
 
I did suggest on the low traffic comp.std.c++ group that standard
library headers that don't require run time (especially dynamic
allocation) support should be identified in the standard. One of these
days I'll follow this up.
 
--
Ian Collins
legalize+jeeves@mail.xmission.com (Richard): Mar 04 09:57PM

[Please do not mail me a copy of your followup]
 
Gareth Owen <gwowen@gmail.com> spake the secret code
 
>int foo[16];
>// fill in values
>std::sort(foo,foo+16);
 
Good point. I wouldn't say you even have to be lazy :-). The form
with begin/end doesn't need to be updated if the number of elements in
the array change later-on. Having to make the same change (16 to 20
for instance) in multiple places in the code is a code smell.
 
The std::begin/end usefulness for fixed length C style arrays comes in
most handy with a range for statement.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Mar 04 09:58PM

[Please do not mail me a copy of your followup]
 
slp53@pacbell.net spake the secret code
 
>SGI had a real C++ compiler (and a pretty good one, too).
 
Only after they had a Cfront based compiler. I know because I was
using their compiler at the point when they switched.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Juha Nieminen <nospam@thanks.invalid>: Mar 04 07:24PM

> You can swap two std::vector instances and keep item references valid.
 
Fair enough. That's probably the only requirement that would be broken
with a "small vector optimization".
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: