Reputation: 12680
Is it safe to loop over Objective-C BOOLs like so:
for (BOOL flagA = NO; flagA <= YES; flagA++)
for (BOOL flagB = NO; flagB <= flagA; flagB++)
// ...
I'd like to use this to cycle through all relevant permutations of flags in a XCTestCase
.
But it appears as if YES++
is still YES
at least on some platforms (hence leading to an infinite loop e.g. on iPhone 6 Plus simulator) whereas I would have expected that BOOL
would just be treated as int
(and hence YES++
becoming 2
).
Do I have to loop over int
s (my best guess) instead, or can the use of BOOL
be salvaged in some convenient way?
Upvotes: 2
Views: 284
Reputation: 3664
You are all missing the point here. Drux is asking why can't he increment over BOOL, while it should be a char (8 bit value), which is perfectly incrementable.
The Answer is very easy. BOOL is sometimes a char and sometimes a bool
depending on the target. From objc.h
file:
#if !defined(OBJC_HIDE_64) && TARGET_OS_IPHONE && __LP64__
typedef bool BOOL;
#else
typedef signed char BOOL;
If you iterate over a bool
you will get value of 1
maximum.
EDIT:
Can you please add a reference to where the semantics of ++ for bool are specified? - Drux
Even though that bool
has to be 8 bits minimum, it can't have any other value than 0
or 1
. Why ? Because bool a = 3
(bool equal operator) converts 3
into a bool
value, which is true
which is 1
.
So bool a = true; a++
is the same as bool a = 2;
which makes a
have a value of 1
Upvotes: 4
Reputation: 9010
If you're set on operating over BOOLs
, then instead of:
for (BOOL flagA = NO; flagA <= YES; flagA++)
for (BOOL flagB = NO; flagB <= flagA; flagB++)
// ...
You should really be doing something this (though it is not what you want):
for (BOOL flagA = NO; flagA != YES; flagA = !flagA)
for (BOOL flagB = NO; flagB != flagA; flagB = !flagB)
// This is the only safe way to 'iterate' BOOLs
The behaviour, (BOOL)++
is not well-defined* as a BOOL
can only be YES
or NO
. What you really should be doing is casting your BOOL
to an int
, and iterating over that, or refactoring your loop entirely to use int
types.
The problem with casting your BOOL
values to ints
is, as you have pointed out, BOOL
is typedef'd to something with only 8 bits of information*, therefore it only makes sense to have 255 iterations. In fact in more recent times, BOOL
is not cast-able at all because it is defined as a compiler intrinsic (objc_bool
, which can have values __objc_yes
and __objc_no
). __objc_no++
has no meaning.
TL;DR My (strong) suggestion would be to refactor your code so you are iterating over integers, and inspecting BOOLs
within each iteration. Whether you cast your BOOL
values, or refactor your loop is up to you, but iterating over BOOL
values in the way you have indicated is both unsafe and (now, because of that) unsupported.
* In past years, the implementation details of BOOL
were obvious (namely a cast to an unsigned char). With the advent of compiler intrinsics, the details are hidden (though they are likely the same). The reason they are now hidden is because you're really not supposed to rely on them, and the easiest way to stop people relying on them is to hide them from the compiler altogether.
Upvotes: 0
Reputation: 16256
I think @Sulthan means something like this (made overly explicit on purpose):
for(int indexA = 0; indexA <= 1; indexA++){
for(int indexB = 0; indexB <= indexA; indexB++){
BOOL flagA = (indexA == 1) ? YES : NO;
BOOL flagB = (indexB == 1) ? YES : NO;
// Use your flags (booleans) here...
}
}
(Of course, you can use just the int
s in place of booleans in Objective-C, if you want to avoid using too many redundant variables).
ADDENDUM: I actually performed a "Jump to definition" in Xcode (OSX project), and the part looks like this:
#if __has_feature(objc_bool)
#define YES __objc_yes
#define NO __objc_no
#else
#define YES ((BOOL)1)
#define NO ((BOOL)0)
#endif
(usr/include/objc/objc.h)
Can't "Jump to Definition" on __objc_yes
(gives "Symbol Not Found")
Upvotes: 0
Reputation: 2722
The only way I see would be adding a break in your loop to escape the infinite loop.
Another possibilities is to use simple integer and stop the for loop when counter == 2
for (BOOL flagA = NO; YES; flagA++) {
for (BOOL flagB = NO; YES; flagB++) {
// Do something
if (flagB)
break;
}
if (flagA)
break;
}
Upvotes: 0