Ошибка "Передача от указателя к меньшему типу" 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;