Reputation: 33126
Apple now requires all iOS code to be 32/64 bit dualistic. That's great - except there's a few of their libraries that don't fully support the duality.
e.g. one project uses NSScanner, which supports "scanInteger" (correct) but no "scanCGFloat" - instead you have to "scanFloat" or "scanDouble" (encoded in the method names!).
UPDATE: NSScanner is a nastier example than I realised; it takes pointers as args.
- (BOOL)scanFloat:(float *)result;
- (BOOL)scanDouble:(double *)result;
...ugh.
It affects a whole bunch of stuff - another example is math.h (similarly: float vs double is encoded in function names), although there you can at least switch to tgmath.h and get rid of the "type-is-in-the-name" silliness.
What's the correct, general, solution to this problem?
Upvotes: 2
Views: 1177
Reputation: 86651
The simplest solution is to scan as a double and then cast the result to CGFloat.
-(CGFloat) scanCGFloat
{
double myDouble;
[scanner scanDouble: &myDouble];
return (CGFloat) myDouble;
}
Use a similar trick for NSInteger and NSUInteger, always scan as a (unsigned) long and cast to NS(U)Integer.
Upvotes: 0
Reputation: 539745
C11 has introduced a new feature "Generic selection" that can be used to
let the compiler choose the right method, depending on the type of CGFloat
.
Written as a NSScanner
category method:
@implementation NSScanner (MyCategory)
-(BOOL) myScanCGFloat:(CGFloat *)cgFloatValue
{
return _Generic(*cgFloatValue,
double: [self scanDouble:(double *)cgFloatValue],
float: [self scanFloat:(float *)cgFloatValue]);
}
@end
Remarks:
_Generic
keyword is described in "6.5.1.1 Generic selection" of the C11 standard (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf). Another description is here:
http://www.robertgamble.net/2012/01/c11-generic-selections.html. CGFloat
is compatible to float
or double
,
not if the current target architecture is 32-bit or 64-bit._Generic
keyword, even in the default GNU99 mode. I have not tested earlier Xcode/Clang versions.Previous answer: One possible solution would be do mimic the definition of CGFloat
and let the preprocessor choose the correct version:
CGFloat f;
#if __LP64__
[scanner scanDouble:&f];
#else
[scanner scanFloat:&f];
#endif
Or you define a custom macro:
#if __LP64__
#define scanCGFloat scanDouble
#else
#define scanCGFloat scanFloat
#endif
// ...
CFFloat f;
[scanner scanCGFloat:&f];
Alternatively, use a temporary variable:
double tmp;
[scanner scanDouble:&tmp];
f = tmp;
Upvotes: 6
Reputation: 33126
For reference (and I feel this is a poor, cludgy solution), my best idea so far is to do:
NB -- I'm using NSScanner as an example, but it's a general problem/solution!
if( sizeof( var ) <= 4 )
[scanner scanFloat:&var];
else
[scanner scanDouble:&var];
...but this will NOT fix the compiler-errors (on both platforms), it'll simply make it "do the right thing at runtime" as a hack. Surely not a good solution?
Upvotes: 1
Reputation: 33126
Ah, routing around in headers, I just found this (NOT mentioend in Apple's official "upgrade to 64bit" docs!!!)
#define CGFLOAT_IS_DOUBLE 1
#define CGFLOAT_IS_DOUBLE 0
...so I guess this is the thing to use?
Upvotes: 1