bool vs. int execution speed and mem size - Page 1
Forum section: electronics / general

author: Jester
author_rank: Frequent Contributor
timestamp: October 30, 2022, 12:01:45 pm
content: I was just thinking about C or C++ compiler optimization and booleans vs. say Uint16 on a 16 bit uCIf I use a boolean, and assuming the compiler packs multiple bools into one memory location. I would assume that at the assembly level the other bits need to be masked when an actual branch occurs, therefore the execution time would be slower with a bool vs. Uint16 simple example...bool onNotOff;.....if ( onNotOff ) {doSomething();}I would also imagine that if the compiler was set to optimize for speed, it might actually use an int instead of single bit within an int to optimize for speed and if set to optimize for size would likely pack a bunch of bools into an int space. Does that make sense?

author: hans
author_rank: Super Contributor
timestamp: October 30, 2022, 12:19:16 pm
content: At first glance it would make sense it's implemented like this, but unfortunately it's not.If you want the feature you're talking about, you need to put the bools into a struct and then pack them yourself. E.g.:Code:struct foo {bool setting1 : 1;bool setting2 : 1;bool setting3 : 1;uint8_t verySmallNumber : 4;bool setting4 : 1;};This struct should only occupy 1 byte. The verySmallNumber field should overflow at 15+1.The compiler now has to go through all the extra trouble to find the bit to test. For boolean, most implementations actually assume false as '==0' and true as any othercase, even though you could say an explicit true value has to be 1 (e.g. check for ==1).The implementation of bool in C(++), is IIRC it uses the same type as an unsigned char. This is also not always the fastest type to use, however, since the arithmetic with bools should be limited to boolean operators only (not bitwise), I wouldn't expect it to have an impact in most cases (although it may be there)Example:https://godbolt.org/z/qvr55bKWY

author: AVI-crak
author_rank: Regular Contributor
timestamp: October 30, 2022, 05:56:22 pm
content: The bool type was originally conceived to be instantaneous when returning from a function. When the function is placed in a condition block. In this case, the flag register is used to fulfill the condition at the return point of the function - "is not equal to zero". External storage of the bool value is not used in this case - the maximum saving of time and resources from all possible options.If the algorithm provides for saving the result for further processing (sometime later) - all the savings evaporate. The size of the bool type is easier to leave to the will of the compiler, it will do it optimally.

author: NorthGuy
author_rank: Super Contributor
timestamp: October 30, 2022, 06:52:58 pm
content: I don't think bools are stored as bit flags. What is more efficient - accessing a bit flag or the whole byte? This depends on the CPU.

author: Rick Law
author_rank: Super Contributor
timestamp: October 30, 2022, 07:25:32 pm
content: Quote from: Jester on October 30, 2022, 12:01:45 pmIt is entirely dependent on compiler's implementation and the option flags selected at compile. Looking at the compiler's output is likely the best and only way to be sure. Also bare in mind, with struct { }, there may be byte/word alignment consideration as well. That would be yet another compiler flag to deal with.One thing for sure is: any use of the bit-field flag will need more complex operation (generated by the compiler). To read, upon retrieving the byte (containing your bool value) from memory, it would need to do a masking op to pick out only the bit your flag such as (ByteWithYourFlag & 0x01) if your flag is at the LSB. The value setting is even more complex - it first has to read the byte with your value. That byte may contain other flags. So it has to shift+mask then "OR" your new value in to the byte first, then store the byte back. All that extra ops verses a single op code to merely store for an "int". You actually may end up consuming more space and running slower unless your compiler is rather smart with optimization.As said, you need to look at the compiler output to be sure if it does save space, or not.

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 30, 2022, 07:45:16 pm
content: A compiler will never "pack" *multiple different variables* in a single integer. It would break too many C features, such as taking a pointer with &, and so on. The only way of doing this is to use bit fields in structs as shown above, or implement your "bit arrays" manually.In practice, booleans in C99+ are stored as individual integers, the width of which depends on the platform. But contrary to using an integer, operations on bool are guaranteed to yield only the 0 or 1 values, any non-zero value being converted to 1.Eg: bool b = 10; // b will contain 1 when cast to an integer (or implicitly converted to one)Due to this feature, bool *can* be less efficient than integers, as they require an extra step to coerce the values to 0 and 1 only, unless the compiler can trivially determine that the underlying expression can't be anything other than 0 and 1. So, that's something to keep in mind. Depending on the target, this coercion can be as simple as one instruction (such as RISC-V), or may require a conditional branch (ouch!)

author: brucehoult
author_rank: Super Contributor
timestamp: October 31, 2022, 04:27:51 am
content: Quote from: AVI-crak on October 30, 2022, 05:56:22 pmAll of what you say is highly dependent on the type of CPU being used, and the C compiler or the ABI it implements, which has not been specified, except that it is a "16 bit uC".So for sure it is not x86 or any flavour of ARM or RISC-V or MIPS, or SUperH, or the 8 bit 6502, z80, 8051, PIC, AVR either. Some of those have flags registers and some don't.I don't recall ever seeing an ABI that specified a bool value could be returned in a flag. That's not to say there isn't one, but I've seen (and implemented) a few ABIs.Also, anyone who is using their time to think about such micro-optimisations, who is not already a programming expert, would probably find much bigger gains from using that time to think about other things, such as algorithms, or testing.

author: JPortici
author_rank: Super Contributor
timestamp: October 31, 2022, 05:58:43 am
content: It's going to be dependand on the device. What does the compiler manual say about boolean types?I see that they are *usually* stored in char sized units (for example in older microchip compilers, in stdbool.h you had bool defined to alias unsigned char, later versions introduced _bool and bool defined to alias _bool)

author: wek
author_rank: Frequent Contributor
timestamp: October 31, 2022, 07:48:41 am
content: > except that it is a "16 bit uC".>> So for sure it is not x86Sure? ;-)JW

author: hans
author_rank: Super Contributor
timestamp: October 31, 2022, 08:25:56 am
content: Quote from: SiliconWizard on October 30, 2022, 07:45:16 pmGood point. A pointer only aligns to byte addresses, and as such, cannot address information more narrowly than at a byte level. If the compiler were to pack bools for you, and you took a pointer to one of those packed bools, then that pointer should also include bit index information. Since pointers are universal (e.g. void* or null-ptr concept) and are most often used for data buffers or struct passing, I don't think any compiler or architecture is going to support bit level pointers any time soon. It would make them incompatible with underlying hardware structures as well (such DMA memory addresses). After all, bools are typically used to switch between predicate statements and not much else.I guess you could write a bit-level pointer implementation in SW, but then each instantiation of that bit-pointer would need to include the memory address (intptr_t) and the bit index (e.g. uint8_t or uint16_t). That would create a pretty large overhead, as well. But I think it's fairly obvious by now that packing the data closer together only has benefits in data memory usage, but not on code memory usage.

author: westfw
author_rank: Super Contributor
timestamp: October 31, 2022, 08:32:07 am
content: C pretty much requires that any primitive value can have a Pointer to it.I think there was a brief period of time when C compiler could have had a single bit boolean type, when ARM did Cotrex-M3 with “bit banding.” But afaik no compiler, and few programmers, ever made much use of that feature, and it’s pretty much no longer implemented

author: newbrain
author_rank: Super Contributor
timestamp: October 31, 2022, 09:55:41 am
content: Quote from: westfw on October 31, 2022, 08:32:07 amI was thinking about this, but even bit banding would not make for a very efficient (C99 and later compliant) boolean type, probably worse in many respect.I see two major issues with it:Any boolean embedded in a structure should be treated specially - as the structure would need to be in regular memory, not the bit band alias - or, alternatively, pointers to bool need to be special. Doable, but not efficient.Bit 0 of the value written to a bit banded location determines its content, so the "!= 0 becomes 1" semantic is not automatic and needs more or less the same conversion logic.A couple of notes on the boolean type:- Booleans are an unsigned integer type, with the lowest possible rank. This tells nothing about their size (i.e., only that sizeof(bool) >= 1)- Conversion of other arithmetic types to booleans works differently from any other conversion. Especially surprising might be converting a complex to bool: a complex containing a pure imaginary value will convert to an integer of float type with a value of 0 (zero), but to a boolean value of 1 (true).- 'bool' is, up to and including C17, a macro defined as _Bool, the native type, in <stdbool.h>. It is, instead, a keyword in C23 (similarly for true and false), and the use of _Bool in the code is deprecated.

author: NorthGuy
author_rank: Super Contributor
timestamp: October 31, 2022, 01:54:58 pm
content: Quote from: westfw on October 31, 2022, 08:32:07 amIf a pointer is never taken, the compiler is free to represent values it as it wishes, single bit is certainly possible. I think we would see that long time ago, but the main C developers think in terms of x86, or aarch64 perhaps. Neither of these would benefit from single bit storage.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: October 31, 2022, 03:24:32 pm
content: The 8051 supports a bit-addressable area of memory (from 0x20 to 0x2F in data memory), and there are compilers that support that (SDCC, Keil, maybe others) which allow you to declare single-bit variables as being in that address space. I'm not familiar with how that works, though - not sure whether the compiler allows pointers to be taken to those variables.

author: Rick Law
author_rank: Super Contributor
timestamp: October 31, 2022, 04:33:37 pm
content: Quote from: NorthGuy on October 31, 2022, 01:54:58 pmEven for an MCU like the 32K arduino, it is hard to save space by using bit storage. Array of struct {bit fields} access via a looped single call (or a few calls) inside loops is about the only way space saving can be had. The overhead in reading/setting them is just too high.

author: AVI-crak
author_rank: Regular Contributor
timestamp: October 31, 2022, 04:57:01 pm
content: Quote from: brucehoult on October 31, 2022, 04:27:51 amI have seen a huge amount of code for autonomous systems, where every complex function produces heavy state structures, or an enumeration to insane depth, and even that same bool. But more often everything at once, and in a global variable.All this data is scrupulously processed in a function, sorted out in the hope of further use.And what do I see as a result? The function call point just ignores all this garbage. At best, save the result in a common wastebasket - to report back to the top with the same result.This is not a hardware test - this is a real working autonomous system code.The bool must be conditionally evaluated at the point of the function call. You can’t delay processing, otherwise the algorithm will turn into a wastebasket.

author: uer166
author_rank: Super Contributor
timestamp: October 31, 2022, 06:01:20 pm
content: Quote from: westfw on October 31, 2022, 08:32:07 amOn M4 I use the bit-banding feature regularly, it's a great way to implement atomic flags in software without disabling interrupts, the RMW is handled in hardware. Putting that feature in as part of compiler would be brain-dead IMO however.

author: NorthGuy
author_rank: Super Contributor
timestamp: October 31, 2022, 06:17:39 pm
content: Quote from: Rick Law on October 31, 2022, 04:33:37 pmPICs can access bits in memory directly.

author: brucehoult
author_rank: Super Contributor
timestamp: October 31, 2022, 09:37:00 pm
content: Quote from: wek on October 31, 2022, 07:48:41 amI'm not aware of Intel making x86 microcontrollers with less than 486+a bit or 586-FPU ISA.I'm certainly open to learning differently.

author: woofy
author_rank: Frequent Contributor
timestamp: November 01, 2022, 09:49:25 am
content: Oh, Bruce.You are wickedly subtle.

author: brucehoult
author_rank: Super Contributor
timestamp: November 01, 2022, 10:44:59 am
content: Quote from: woofy on November 01, 2022, 09:49:25 am?? Just taking OP at their word.

author: Rick Law
author_rank: Super Contributor
timestamp: November 01, 2022, 04:25:48 pm
content: Quote from: NorthGuy on October 31, 2022, 06:17:39 pm+1 for PICs then! With the limited EEPROM and Flash storage (for data-logging), bit fields is helpful and direct bit-in-memory access made that even sweeter.

author: SiliconWizard
author_rank: Super Contributor
timestamp: November 01, 2022, 07:49:29 pm
content: But you'll get the same with either struct bit fields or your own bit arrays using masks and basic logic operations, in a portable way. And using any modern MCU that will easily beat any old PIC in terms of performance doing that rather than using bit access instructions in assembly on a few-MHz MCU with a crippled architecture. Just saying.

author: wek
author_rank: Frequent Contributor
timestamp: November 01, 2022, 11:31:37 pm
content: Quote from: brucehoult on October 31, 2022, 09:37:00 pmWho said Intel?https://www.amd.com/system/files/TechDocs/21914.pdfhttps://en.wikipedia.org/wiki/NEC_V25Of course it was just a joke.JW

author: brucehoult
author_rank: Super Contributor
timestamp: November 02, 2022, 03:52:01 am
content: Quote from: wek on November 01, 2022, 11:31:37 pmLearn something every day. Looks like both went out of production well before I had anything to do with microcontrollers.Also, the AMD chip is clearly a microprocessor not a microcontroller by modern definitions, having zero internal RAM or ROM. The NEC seems to be mostly based on external RAM and ROM also -- there is 256 bytes of internal RAM, and 8 K of internal ROM described as "reserved". I didn't manage to learn whether that is dedicated to microcoding or whether a customer could specify (some) of its contents.

author: bson
author_rank: Unknown
timestamp: November 04, 2022, 08:17:34 pm
content: Quote from: wek on November 01, 2022, 11:31:37 pmSurprised the AM186 is still around... I worked a bit with the AM188ES and AM186ES almost 20 years ago, and it was a nice uC for the time. Segment registers aren't bad when you don't try to use them to extend the address space beyond 16-bit segments. I thought AMD stopped making it though, and licensed it to third parties - but I can imagine there are millions of existing products out there using some variant of it.

author: spth
author_rank: Regular Contributor
timestamp: May 11, 2023, 01:43:57 pm
content: Quote from: HwAoRrDk on October 31, 2022, 03:24:32 pmWhen targeting MCS-51, SDCC will try to put some local bool variables into such bit memory to save RAM.