Tuesday, February 23, 2016

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

Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Feb 23 10:19PM

Code containing asserts will behave differently depending on whether or
not the macro NDEBUG is defined. This is dangerous as it may result in
undetected bugs in a release build manifesting as undefined behaviour
that doesn't cause a straight crash but does something more serious.
 
One should prefer exceptions to asserts. One should have many exception
types and many throws (a throw statement should have no performance
impact in a decent implementation for the code path where no exception
is thrown) but few try/catches.
 
I recommend having a top level try/catch in main() and a few other
try/catches where appropriate (for exceptional cases that are
recoverable without terminating the application).
 
Remember: asserts considered harmful.
 
/Flibble
Ian Collins <ian-news@hotmail.com>: Feb 24 11:27AM +1300

Mr Flibble wrote:
> not the macro NDEBUG is defined. This is dangerous as it may result in
> undetected bugs in a release build manifesting as undefined behaviour
> that doesn't cause a straight crash but does something more serious.
 
So don't change NDEBUG in your release builds.
 
--
Ian Collins
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Feb 23 10:32PM

On 23/02/2016 22:27, Ian Collins wrote:
>> undetected bugs in a release build manifesting as undefined behaviour
>> that doesn't cause a straight crash but does something more serious.
 
> So don't change NDEBUG in your release builds.
 
You are assuming everyone does that: they don't.
 
/Flibble
Ian Collins <ian-news@hotmail.com>: Feb 24 11:44AM +1300

Mr Flibble wrote:
>>> that doesn't cause a straight crash but does something more serious.
 
>> So don't change NDEBUG in your release builds.
 
> You are assuming everyone does that: they don't.
 
I'm not assuming, I'm recommending.
 
--
Ian Collins
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 24 12:00AM +0100

On 23.02.2016 23:19, Mr Flibble wrote:
> not the macro NDEBUG is defined. This is dangerous as it may result in
> undetected bugs in a release build manifesting as undefined behaviour
> that doesn't cause a straight crash but does something more serious.
 
Well, you can define a wrapper that throws an exception in NDEBUG
(a.k.a. "release") mode, then preferably a "hard exception" that has
maximum chances of propagating all the way up to `main`.
 
The main problem with that, as I see it, is that cleanup via stack
unwinding can be dangerous when an assertion has failed.
 
But I think the chances favor attempted cleanup as typically less
destructive, less costly to the user, than a simple crash or just
continuing with UB, which can do all kinds of Very Bad Things™. Of
course one might ask the user. That's what the robots in Asimov's novels
failed to consider, to just ask those that they served, before going all
out with xenocide of the galaxy and mind control of humans.
 
Anyway, as bonus points such a wrapper can do away with the silly
restriction that the `assert` argument must be of scalar type (in C++ it
can be enough that it's convertible to `bool`); the wrapper can possibly
include logging; and the wrapper can be `constexpr`, which unfortunately
is not guaranteed for plain `assert`.
 
See <url:
https://github.com/alf-p-steinbach/cppx/blob/master/source_code/cppx/basics/execution/assertions/CPPX_ASSERT.hpp>
for an example (does not include logging, nor asking, but is `constexpr`).
 
 
> types and many throws (a throw statement should have no performance
> impact in a decent implementation for the code path where no exception
> is thrown) but few try/catches.
 
I think this is much like an argument that one should prefer runtime
type checking, namely based on a conflation of issues, and designed to
make one particular chosen approach to things seem preferable.
 
An assertion expresses an INCORRECT ASSUMPTION, strongly associated with
preconditions.
 
This is a contract breach by a caller, or by preceding code, and it
indicates something wrong up there, often with no way to be sure exactly
where or what.
 
Throwing an ordinary exception misinforms the calling code, which will
handle the ordinary exception as if this code, not itself, had failed.
 
An exception (a standard exception) throwing, OTOH., expresses a GOAL
ACHIEVEMENT FAILURE, strongly associated with postconditions.
 
This is a local failure. One knows what's wrong, e.g. some resource
exhausted, some item not found, whatever, including the case where some
lower level function failed, possibly via exception. And the design
called for such failure to be communicated back up via an exception.
 
 
> I recommend having a top level try/catch in main() and a few other
> try/catches where appropriate (for exceptional cases that are
> recoverable without terminating the application).
 
Yes, I agree that's useful.
 
In particular, otherwise a Windows GUI subsystem program can just
silently terminate...
 
And there's also the issue of stack unwinding not being guaranteed for
an unhandled exception.
 
 
> Remember: asserts considered harmful.
 
No. :)
 
 
Cheers!,
 
- Alf
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Feb 23 11:20PM

On 23/02/2016 23:00, Alf P. Steinbach wrote:
> exhausted, some item not found, whatever, including the case where some
> lower level function failed, possibly via exception. And the design
> called for such failure to be communicated back up via an exception.
 
Not true: std::logic_error is meant for coding errors including
incorrect assumptions. One should derive custom exceptions from
std::logic_error and throw these instead of asserting.
 
/Flibble
bitrex <bitrex@de.lete.earthlink.net>: Feb 23 04:45PM -0500

On 02/23/2016 04:34 PM, David Brown wrote:
> parts (on the ARM, 8-bit, 16-bit and 32-bit types all have "natural"
> alignments), and the ordering of the bitfields (which is low bits first
> - guaranteed by the ARM EABI, and thus consistent across compilers).
 
"Naughty" if one wants to port the code as-is to another architecture, I
guess.
Tim Wescott <seemywebsite@myfooter.really>: Feb 23 03:53PM -0600

On Tue, 23 Feb 2016 14:17:59 -0500, bitrex wrote:
 
> frac_high : 8, frac_low : 8;
 
> };
> } phase_accumulator;
 
First:
 
Yes, it'll work as long as you want the least significant byte to be
named "integer_high" and the most significant byte to be named "frac_low".
 
Second:
 
You need to name the bitfield. I'll assume you've named it "bits" --
i.e., phase_accumulator.bits.frac_high.
 
Third:
 
It should be just as fast to use:
 
uint32_t phase_accumulator;
 
static inline uint8_t integer_high(uint32_t x) {return (x >> 24) & 0xff;}
static inline uint8_t integer_low (uint32_t x) {return (x >> 16) & 0xff;}
static inline uint8_t frac_high (uint32_t x) {return (x >> 8) & 0xff;}
static inline uint8_t frac_low (uint32_t x) {return (x >> 0) & 0xff;}
 
This will be portable, and integer_high(phase_accumulator) should read as
easily (or more so) as phase_accumulator.bits.integer_high.
 
--
 
Tim Wescott
Wescott Design Services
http://www.wescottdesign.com
David Brown <david.brown@hesbynett.no>: Feb 23 11:21PM +0100

On 23/02/16 22:45, bitrex wrote:
>> - guaranteed by the ARM EABI, and thus consistent across compilers).
 
> "Naughty" if one wants to port the code as-is to another architecture, I
> guess.
 
I would say "non-portable" rather than "naughty". "Naughty" implies
that this might not work in some circumstances, or perhaps depends on
undefined behaviour. This is merely non-portable and relies on
implementation-dependent behaviour (which happens to be defined by the
ARM EABI, and thus should apply to all ARM compilers).
David Brown <david.brown@hesbynett.no>: Feb 23 11:48PM +0100

On 23/02/16 22:53, Tim Wescott wrote:
 
> First:
 
> Yes, it'll work as long as you want the least significant byte to be
> named "integer_high" and the most significant byte to be named "frac_low".
 
True.
 
> Second:
 
> You need to name the bitfield. I'll assume you've named it "bits" --
> i.e., phase_accumulator.bits.frac_high.
 
Not necessary true, assuming you are using C11 (rather than C++), or gcc
or clang, or any other compiler that supports anonymous structs as an
extension. Since this is specifically for the ARM, and not meant to be
portable, it is perhaps not unreasonable to use an extension that is
available the most common tools for that target. But that's a decision
for the OP to make.
 
> static inline uint8_t frac_low (uint32_t x) {return (x >> 0) & 0xff;}
 
> This will be portable, and integer_high(phase_accumulator) should read as
> easily (or more so) as phase_accumulator.bits.integer_high.
 
No, these functions are not a good substitute. First, they do not do
the same thing if "phase_accumulator" is used as a volatile - and such
bitfield structures are usually used for hardware registers where
volatile is relevant. Using the bitfields, accesses to the separate
fields will be done as 8-bit accesses - using the functions, they will
be 32-bit accesses.
 
Second, your functions give read-only access, not read-write access -
another set is needed for writing. Those are messy.
 
static inline uint32_t set_integer_low (uint32_t x, uint8_t y) {
return (x & 0xff00ffff) | ((uint32_t) y << 16);
}
 
 
Third, your functions will /not/ be as fast for volatile types, and the
write versions may be significantly slower.
 
Fourth, your functions are ugly in use, especially for setting:
 
phase_accumulator = set_integer_low(phase_accumulator, y)
 
(I'm continuing your slight mixup of treating "phase_accumulator" as the
instance of the union, rather than the type.)
 
Fifth, you lose one of the major reasons for using bitfields rather than
bitmasks. With bitfields, the field is tied tightly to the type, and
therefore the instance of the type. Mistakes are compile-time errors,
your IDE can quickly give you assistance at filling out the field names,
and your debugger can parse the data. With manual shift-and-mask
systems you lose all of that.
 
 
The cost of using bitfields here is that the code is not directly
portable to other targets unless they have the same assumptions about
bitfield ordering and alignment (and in reality, most targets do match
here). IMHO, it's a small price to pay.
Jerry Stuckle <jstucklex@attglobal.net>: Feb 23 11:19AM -0500

On 2/23/2016 10:01 AM, Cholo Lennon wrote:
 
> Some of them seem weird to me (like gcc usage on Windows)
 
> Regards
 
With no information on how the "research" was done, the results of any
survey is questionable.
 
--
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
Cholo Lennon <chololennon@hotmail.com>: Feb 23 01:52PM -0300

On 02/23/2016 01:19 PM, Jerry Stuckle wrote:
 
>> Regards
 
> With no information on how the "research" was done, the results of any
> survey is questionable.
 
Yeah, you're right, they didn't say that; and when someone asked about
data inconsistencies, the author said the following:
 
"The point is that various data has come from various data sources, that
can be influenced by many factors. When we got some data on the same
topic from different sources, we were trying to get some average"
 
It would be nice to know the data sources.
 
The positive side is that JetBrains has developed its CLion product
using the mentioned research (at least that's what they say)
 
 
Regards
 
 
--
Cholo Lennon
Bs.As.
ARG
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: