在将Xcode升级到5.1(5B130a)后,在EAGLView.mm中出现错误:“从指针向较小类型'int'的转换丢失信息”。

32

昨天,我更新了Xcode到最新版本(5.1 (5B130a))以兼容iOS 7.1。然后我构建我的项目时,当选择64位模拟器(例如:iPhone Retina 4英寸64位)时,在EAGLView.mm文件(第408行)中出现错误"Cast from pointer to smaller type 'int' loses information"

我正在使用cocos2d-x-2.2.2。在更新Xcode之前,我的项目仍然可以在所有设备上正常构建和运行。

感谢所有的建议。

更新:今天,我下载了最新版本的cocos2d-x(cocos2d-x 2.2.3)。但是问题仍然存在。

以下是出错代码的一部分:

/cocos2d-x-2.2.2/cocos2dx/platform/ios/EAGLView.mm:408:18: Cast from pointer to smaller type 'int' loses information

// Pass the touches to the superview
#pragma mark EAGLView - Touch Delegate
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (isKeyboardShown_)
    {
        [self handleTouchesAfterKeyboardShow];
        return;
    }

    int ids[IOS_MAX_TOUCHES_COUNT] = {0};
    float xs[IOS_MAX_TOUCHES_COUNT] = {0.0f};
    float ys[IOS_MAX_TOUCHES_COUNT] = {0.0f};

    int i = 0;
    for (UITouch *touch in touches) {
        ids[i] = (int)touch;     // error occur here
        xs[i] = [touch locationInView: [touch view]].x * view.contentScaleFactor;;
        ys[i] = [touch locationInView: [touch view]].y * view.contentScaleFactor;;
        ++i;
    }
    cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesBegin(i, ids, xs, ys);
}

如果指针是64位,而整数是32位,则整数太小无法容纳指针值。 - 001
谢谢。但我不想编辑“EAGLView.mm”中的代码,因为它是一个“库文件”。无论如何,当我使用iOS 7.0的Xcode 5.0时,项目仍然可以正常构建和运行。问题只出现在Xcode 5.1上。 - nvg58
问题之前就存在了,只是现在你被告知了而已。无论它是否真的是个问题,这都是另一个问题。 - CodeSmile
@LearnCocos2D:那么,我如何在不编辑任何非我的代码或库文件行的情况下“克服”错误呢? - nvg58
2
如果它与cocos2d-iphone v2.x类似,并且仅基于核心类中的这个代码片段,我敢打赌cocos2d-x 2.x也不兼容64位代码,并且您可能会遇到各种问题(不仅是编译时而且还包括运行时)。除了寻找或希望修复2.x版本或升级到3.x之外,您可能几乎无能为力(我认为它是64位安全的,但这只是一个猜测,在升级之前请研究此问题)。唯一的选择就是花时间解决所有64位代码问题,其中可能存在一些非微不足道的问题。 - CodeSmile
显示剩余2条评论
6个回答

50

显然,Xcode 5.1及以上版本中的clang版本对源代码中可能存在的32位与64位不兼容性更加严格,比起早期的clang版本。

老实说,我认为clang在这里太过于限制了。一个明智的编译器可以在类似这样的行上发出警告,但它绝不能抛出错误,因为这段代码并没有错,只是可能存在错误风险,但完全可以合法。

原始代码如下

ids[i] = (int)touch;

其中ids是一个整数数组,touch是一个指针。

在64位构建中,指针是64位的(与32位构建相反,它是32位的),而int是32位的,因此这个赋值将64位值存储在32位存储器中,可能会导致信息丢失。

因此,编译器对于像这样的一行代码抛出错误是完全有效的。

ids[i] = touch;

然而,实际的代码中涉及到一个显式的 C 风格转换为 int。这个明确的转换告诉编译器:“闭嘴,我知道这段代码看起来不正确,但我知道我在做什么。”

因此,编译器非常挑剔,在让代码重新编译并仍然显示与 Xcode 5.0 相同行为的正确解决方案是:首先将其转换为与指针大小匹配的整数类型,然后再进行第二次转换以获得我们实际想要的 int 类型。

ids[i] = (int)(size_t)touch;

我在这里使用size_t,因为它的大小始终与指针相同,无论平台如何。long long在32位系统上无法工作,而long在64位Windows上无法工作(而64位Unix和类Unix系统如OS X使用LP64数据模型,在其中long为64位,64位Windows使用LLP64数据模型,在其中long的大小为32位 (http://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models))。


3
(int)boo替换为(int)(size_t)boo解决了我的问题。谢谢! - Rafael Ruiz Muñoz
它也解决了我的问题。我希望你先写那些答案,然后再解释。 - nafsaka

9
我也遇到了这个问题。
ids[i] = (int)touch; // error occur here => I change this to below.

ids[i] = (uintptr_t)touch;

然后我就能继续编译了。也许你也可以尝试这样做。

2

XCode 5.1将所有架构改为了64位。

您可以通过以下方式在Build Settings中支持32位编译:

  • 在Architecture中使用$(ARCHS_STANDARD_32_BIT),而不是$(ARCHS_STANDARD)
  • 在Valid Architectures中删除arm64

希望这有所帮助。


我是否需要面对意外的运行时问题? - nvg58
我想不是,我在另一个讨论中找到了相关信息。
  • https://dev59.com/cmMk5IYBdhLWcg3w2RaT
或者至少,我认为cocos2d-x-3.0rc0已经解决了这个问题。
- Peeradon Tadsanaborrisut

2
你可以通过替换这行代码来解决这个错误。
ids[i] = (uint64_t)touch;

由于类型“ int”仅支持-32768〜32768,因此应基于64位构建系统执行类型转换。


因为类型 "int" 仅支持 -32768 ~ 32768,这是不正确的。对于任何现代桌面或移动操作系统或任何 cocos2d-x 支持的操作系统都不是如此。在它们所有的操作系统上,int 都是32位而不是16位。 - Kaiserludi

0

显然,解决方案是将id的类型从int更改为足够大以容纳指针的类型。

我不熟悉XCode,但解决方案应该类似于以下内容:

将ids的声明更改为:

intptr_t ids[IOS_MAX_TOUCHES_COUNT];

并将产生错误的行更改为:

ids[i] = (intptr_t)touch;

上述大部分“解决方案”在将指针强制转换为较小类型时可能会丢失部分指针地址。如果该值再次用作指针,那将证明这是一个极其糟糕的想法。


2
你是正确的,但是cocos实际上只将该地址用作唯一标识符。更改id类型可能是最干净的解决方案,但当我自己面临这个问题时,我决定反对它,因为它只会引入许多依赖于ids为int数组的其他代码的问题。只需加强Xcode 5.0及之前版本的旧行为,通过将其强制转换为int来切掉地址的部分,这不会引入任何新错误,并避免了学习和理解大量实现内部cocos代码的需要。 - Kaiserludi

-2
ids[i] = (int)touch; put * and check it.
ids[i] = *(int *)touch;

1
这个答案是不正确的,原因已经在http://stackoverflow.com/a/22474752/404734的评论中提到了。 - Kaiserludi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接