Objective C测试int是否为long / CGFloat是float还是double

时间:2013-12-22 17:07:27

标签: ios objective-c c

Apple现在要求所有iOS代码都是32/64位二进制代码。这很好 - 除了他们的一些库不完全支持二元性。

e.g。一个项目使用NSScanner,它支持“scanInteger”(正确)但没有“scanCGFloat” - 而是你必须“scanFloat”或“scanDouble”(用方法名称编码!)。


更新:NSScanner是一个比我意识到的更糟糕的例子;它需要指针作为args。

- (BOOL)scanFloat:(float *)result;
- (BOOL)scanDouble:(double *)result;

...啊。


它会影响一大堆东西 - 另一个例子是math.h(类似:float vs double在函数名中编码),虽然你可以至少切换到tgmath.h并摆脱“type-is这个名字“愚蠢。”

这个问题的正确,一般的解决方案是什么?

4 个答案:

答案 0 :(得分:6)

C11引入了一项可用于“通用选择”的新功能 让编译器选择正确的方法,具体取决于CGFloat的类型。

写为NSScanner类别方法:

@implementation NSScanner (MyCategory)

-(BOOL) myScanCGFloat:(CGFloat *)cgFloatValue
{
    return _Generic(*cgFloatValue,
                    double: [self scanDouble:(double *)cgFloatValue],
                    float: [self scanFloat:(float *)cgFloatValue]);
}

@end

说明:

  • _Generic关键字在C11标准(http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)的“6.5.1.1通用选择”中描述。另一种描述如下: http://www.robertgamble.net/2012/01/c11-generic-selections.html
  • 选择匹配代码由编译器完成,而不是在运行时完成。
  • 选择会检查CGFloat是否与floatdouble兼容, 不是当前目标体系结构是32位还是64位。
  • 此解决方案不依赖于任何预处理器宏。
  • 从Xcode 5.0.2开始,Clang支持_Generic关键字,即使在默认的GNU99模式下也是如此。我没有测试过早期的Xcode / Clang版本。

上一个回答: 一种可能的解决方案是模仿CGFloat的定义 并让预处理器选择正确的版本:

CGFloat f;

#if __LP64__
    [scanner scanDouble:&f];
#else
    [scanner scanFloat:&f];
#endif

或者您定义自定义宏:

#if __LP64__
#define scanCGFloat scanDouble
#else
#define scanCGFloat scanFloat
#endif

// ...
CFFloat f;
[scanner scanCGFloat:&f];

或者,使用临时变量:

double tmp;
[scanner scanDouble:&tmp];
f = tmp;

答案 1 :(得分:1)

供参考(我觉得这是一个糟糕的,狡猾的解决方案),到目前为止,我最好的想法是:

注意 - 我正在使用NSScanner作为示例,但这是一个普遍的问题/解决方案!

if( sizeof( var ) <= 4 )
    [scanner scanFloat:&var];
else
    [scanner scanDouble:&var];

...但这不会修复编译器错误(在两个平台上),它只会使它“在运行时做正确的事情”作为黑客攻击。肯定不是一个好的解决方案?

答案 2 :(得分:1)

啊,在标题中路由,我刚发现这个(在Apple的官方“升级到64位”文档中不是mentioend !!!)

  

#define CGFLOAT_IS_DOUBLE 1

     

#define CGFLOAT_IS_DOUBLE 0

...所以我猜这是用的东西?

答案 3 :(得分:0)

最简单的解决方案是扫描为double,然后将结果转换为CGFloat。

-(CGFloat) scanCGFloat
{

    double myDouble;
    [scanner scanDouble: &myDouble];
    return (CGFloat) myDouble;
}

对NSInteger和NSUInteger使用类似的技巧,始终扫描为(无符号)长并转换为NS(U)整数。