- asserts considered harmful - 6 Updates
- Union of bitfields and larger type on ARM - 4 Updates
- Statistics about C++ - 2 Updates
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:
Post a Comment