Ошибка "Передача от указателя к меньшему типу" int "теряет информацию" в EAGLView.mm при обновлении Xcode до 5.1 (5B130a)

Вчера я обновил Xcode до последней версии (5.1 (5B130a)) для совместимости с iOS 7.1. Затем я создаю свой проект, я получаю ошибку "Cast from pointer to smaller type 'int' loses information" в файле EAGLView.mm (line 408), когда выбраны 64-разрядные симуляторы (например, iPhone Retina 4-inch 64-bit).

Я использую 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);
}

Ответы

Ответ 1

Очевидно версия clang в Xcode 5.1 и выше более строга относительно потенциальных 32-битных и 64-битных несовместимостей в исходном коде, чем старые версии clang. Честно говоря, я думаю, что лязг здесь слишком ограничен. Разумный компилятор может выдавать предупреждение в таких строках, но он ни в коем случае не должен выдавать ошибку, потому что этот код НЕ неправильный, он просто подвержен ошибкам, но может быть совершенно допустимым.

Оригинальный код

ids[i] = (int)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)).

Ответ 2

Замените этот ids[i] = (int)touch; с ids[i] = (uintptr_t)touch;

Меня устраивает.

Ответ 3

Я тоже встречаюсь с этой проблемой.

ids[i] = (int)touch;//здесь возникает ошибка = > Я изменяю это ниже.

ids[i] = (uintptr_t)touch;

Затем я могу продолжить компиляцию. Возможно, вы тоже можете попробовать.

Ответ 4

вы можете использовать uintptr_t вместо int. его стандарт следует за Xcode.

Ответ 5

XCode 5.1 изменяет всю архитектуру на 64 бит.

вы можете просто изменить архитектуру для поддержки 32-битной компиляции, как показано ниже в разделе "Настройки сборки"

  • используйте $(ARCHS_STANDARD_32_BIT) в архитектуре вместо $(ARCHS_STANDARD)
  • удалить arm64 в Действительных Архитектурах

Надеюсь, что это поможет.

Ответ 6

Конечно, решение состоит в том, чтобы изменить тип идентификаторов от int до типа, достаточно большого, чтобы удерживать указатель.

Я не знаком с XCode, но решение должно быть примерно следующим:

Измените объявление идентификаторов на:

intptr_t ids[IOS_MAX_TOUCHES_COUNT];

и строка, создающая ошибку:

ids[i] = (intptr_t)touch;

Большинство "решений" выше могут потерять часть адреса указателя при отбрасывании на меньший тип. Если значение всегда используется как указатель снова, что окажется очень плохой идеей.

Ответ 7

Вы можете исправить эту ошибку, заменив эту строку кода.

ids [i] = (uint64_t) touch;

Вы должны выполнить преобразование типов на основе 64-битной системы сборки, потому что тип "int" поддерживает только -32768 ~ 32768.

Ответ 8

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