https://learn.microsoft.com/en-us/windows/win32/winprog/wind...
This must be a pretty slow news day for this to make the front page of Hacker News.
Which makes sense. So these are really only intended to be used for FFI, not internal Delphi code. If you are bridging from C where bools are a byte you want to determine how you handle the other values.
I think the one thing missing is specifying what the True and False constants map to. It is implied that False maps to 0 by "A WordBool value is considered False when its ordinality is 0" but it doesn't suggest that True has a predictable value which would be important for FFI use cases.
And a std::vector<bool> uses 1 bit per bool.
I believe everybody uses a single byte for that -- a single byte can store the values 0 and 1 -- but it looks like they aren't required to.
I believe C++ specifies "bool" is one byte; it's definitely never larger than a "char".
As far as std::vector<bool>, the fact that each value is defined at taking up a single bit inside the std::vector<bool> doesn't really say anything about how large each bool would be outside of the std::vector<bool>. std::vector<bool> was arguably a case of the Committee being too clever ( https://isocpp.org/blog/2012/11/on-vectorbool ).
Although this does open interesting cases where if you read a bool from one FFI interface and write to another it may have an unexpected value (ex 2). But I still think it is useful for the in-language conversions for example Boolean to LongBool and the True constant to have predictable values.
(Tangentially, VB traditionally used -1 for true. VB.NET uses the same 0 or 1 internal representation for a bool as C# but if you convert a bool to a number in VB.NET it comes out as -1.)
The main reason for this particular arrangement is that, so long as you can rely on truth being represented as -1 - i.e. all bits set - bitwise operators double as logical ones. Thus BASIC would have NOT, AND, OR, XOR, IMP, EQV all operating bitwise but mostly used for Booleans in practice (it misses short-circuiting, but languages of that era rarely defaulted to it).
The less serious proposal: have it be `long void`
#include <stdio.h>
typedef struct {} unit;
static unit f(unit *p)
{
return (unit){};
}
static void g(unit u)
{
}
int main()
{
unit a = {}, b = {};
a = b;
f(&a);
g(b);
printf("a is at %lx, b is at %lx, "
"sizeof unit is %d\n",
(unsigned long)&a, (unsigned long)&b,
(int)sizeof(unit));
return 0;
}
compiles without complaints on my cellphone and produces the output:a is at 7ffb39805b, b is at 7ffb39805a, sizeof unit is 0
So you can declare empty structs as variables, return them, assign them, pass them as parameters, take their addresses, create them in struct literals, and dereference pointers to them. clang is assigning different addresses to different empty-struct local variables, but presumably in an array all of them would have the same address, unlike in C++.
I wouldn't be confident that you could malloc them, and I wouldn't be surprised if passing them by value uncovered compiler divergences in the interpretation of the ABI. (I spent most of last night tracking down a bug due to LuaJIT/GCC ABI differences in the implementation of parameter passing.)
IIRC things get a bit funky using this in certain situations, so I'm not sure the compiler devs actually considered this or if it's just a happy accident of sorts.
Fair point, though for me that was a feature when I used it in Delphi. Allowed me to differentiate them when using them as type parameters (generics).
C++ has vector<bool>, which is supposed to be an efficient bit-packed vector of Booleans, but due to C++ constraints it doesn’t quite behave like a container (unlike other vector<T>s). Of course, if you make a vector<bool> of a single bit, that’s still going to occupy much more than one bit in memory.
There are plenty of hardware specification languages where it’s trivial to “allocate” one bit, but those aren’t allocating from the heap in a traditional sense. (Simulators for these languages will often efficiently pack the bits in memory, but that’s more of an implementation detail than a language guarantee).
"Note: The ByteBool, WordBool, and LongBool types exist to provide compatibility with other languages and operating system libraries."
Please downvote it to oblivion.
It's just inefficient, but sometimes needed (MMIO, inter-cpu visible byte changes, etc)
It is not a given that a C/C++ char is a "byte" in the conventional modern understanding of that word, though. sizeof(char)==sizeof(bool)===sizeof(int)==1 is a perfectly valid arrangement for an architecture that is only capable of addressing machine words, and there have been such architectures historically although I'm not sure any are still around today.
EDIT: never mind, guess I misremembered! it's just mandated to be at least 8 bits