О чем надо помнить, создавая 64-битные приложения ООО «СиПроВер» www.viva64.com Преимущества 64-битных приложений • Возможность хранить все данные в памяти • Повышение скорости работы (условие - правильно выбранный формат данных) • Повышение скорости работы за счет архитектурных решений • Отсутствие затрат на прослойку WoW64 Различия при программировании Кто пишет идеальный сферический код? • Различий нет. Си/Си++ это язык для разработки кроссплатформенных программ • Изменилась только модель данных • Но на практике, программы не полностью кроссплатформенны • Скомпилированная 64-битная программа != корректно работающая 64-битная программа Что изменилось? • Размер указателя: 4 байта -> 8 байт. • Размер типов size_t, ptrdiff_t, intptr_t, uintptr_t, INT_PTR, UINTPTR_T: 4 байта -> 8 байт. • Выравнивание данных. Помните при сериализации структур. • Размер индекса массивов. • Так мало? Этого более чем достаточно для проблем! От простого к сложному. Магические числа hFileMapping = CreateFileMapping( (HANDLE) 0xFFFFFFFF, NULL, PAGE_READWRITE, (DWORD) 0, (DWORD) (szBufIm), (LPCTSTR) &FileShareNameMap[0]); //Число 0xFFFFFFFF имеет тип “usigned int”. Правильно: #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) Хранение указателя в 32-битной переменной char *ptr = ...; int n = (int) ptr; ... ptr = (char *) n; Очень неприятная ошибка. Может проявляться только после длительного времени работы программы. Самое важно, что нужно запомнить, создавая 64-битные приложения • Указатель, это не тоже самое, что int или long. Кстати, тип long разный в LP64 и LLP64. это добавляет путаницы. • Не смешивайте 32-битные типы и адресную арифметику. Используйте: – – – – – size_t ptrdiff_t intptr_t uintptr_t INT_PTR, …. Более творческое решение для хранения указателей int *p1, *p2; .... char str[128]; sprintf(str, "%X %X", p1, p2); int *p1, *p2; sscanf(str, "%X %X", &p1, &p2); Для печати значений указателей существует “%p”. Часто неправильно печатают и переменные типа size_t. Следует использовать “%Iu”. const char *invalidFormat = "%u"; size_t value = SIZE_MAX; printf(invalidFormat, value); Ещё о функциях с переменным количеством аргументов Неявное приведение типа unsigned n = it->find("ABC"); if (n != string::npos) return true; Адресная арифметика. Знаковые и беззнаковые типы float p1[100]; unsigned x = 5; int y = -1; float *p2 = p1 + 50; p2 = p2 + x * y; // Access violation *p2 = 1.0f; Правильный код!!!!!!!!!!!!!!!!!!!!!!!!!! Адресная арифметика. Переполнения. extern int Width, Height, Depth; size_t GetIndex(int x, int y, int z) { return z * Width * Height + y * Width + x; } ... MyArray[GetIndex(x, y, z)] = 0.0f; Такие ошибки проявляют себя только на БОЛЬШИХ объемах данных. В результате, не помогут юнит тесты. Не поможет запуск динамических анализаторов, таких как Bounds Checker (слишком медленно). return size_t(z) * Width * Height + size_t(y) * Width + x; О неправильных решениях return size_t(z * Width * Height + y * Width + x); return size_t(z) * Width * Height + y * Width + x; Вечные циклы P.S. Самое забавное, что иногда вечный цикл не возникает. Сказывается оптимизация, выполняемая компилятором. Устаревшие typedef и #ifdef // Самодельность в одном из файлов typedef unsigned UINT_PTR; #ifdef _MY_BUILD_32 // Win32 const unsigned BufferSize = 1024*1024; #else // Win16 const unsigned BufferSize = 16*1024; #endif Из экзотического: переполнение буфера Рост размеров структур struct { bool char int }; MyStruct m_bool; *m_pointer; m_int; struct { char int bool }; MyStructOpt *m_pointer; m_int; m_bool; Другие проблемы • Использование устаревших функций (SetClassLong, GetClassLong, GetFileSize, EnumProcessModules, GlobalMemoryStatus) • Необъявленные функции в Си • Различия в параметрах виртуальных функций • Изменение типа массива • Указатели в объединениях • Исключения • И так далее… Что поможет подготовить надежную 64-битную версию продукта? • Юнит-тесты (полагаться только на них нельзя) • Регрессионные тесты • Устранение предупреждений компилятора • Использование специализированных инструментов. Например, набор правил Viva64 в статическом анализаторе кода PVSStudio. PVS-Studio • Наборы правил: – Самый мощный анализ 64-битных ошибок среди аналогичных инструментов – Диагностики общего назначения – Микрооптимизации – OpenMP • Об инструменте: http://www.viva64.com/ru/pvs-studio/ • Скачать: http://www.viva64.com/ru/pvs-studio-download/ Интеграция с Visual Studio Интеграция с C++Builder Полезные ссылки • Уроки разработки 64-битных приложений на языке Си/Си++. http://www.viva64.com/ru/l/ • Статья. Коллекция примеров 64-битных ошибок в реальных программах. http://www.viva64.com/ru/a/0065 • Обзоры различных статей http://www.viva64.com/ru/r/tag/x64/ • База знаний http://www.viva64.com/ru/k/