SlideShare a Scribd company logo
Как стандарт C++0x поможет в борьбе
с 64-битными ошибками
Автор: Андрей Карпов

Дата: 28.02.2010

Программисты видят в стандарте C++0x возможность использовать лямбда-функции и прочие
мало понятные для меня сущности :). Я увидел в нем удобные средства, позволяющие исключить
многие 64-битные ошибки.

Рассмотрим функцию, которая возвращает true, если хотя бы в одной из строк встречается
последовательность "ABC".

typedef vector<string> ArrayOfStrings;

bool Find_Incorrect(const ArrayOfStrings &arrStr)

{

    ArrayOfStrings::const_iterator it;

    for (it = arrStr.begin(); it != arrStr.end(); ++it)

    {

        unsigned n = it->find("ABC");

        if (n != string::npos)

         return true;

    }

    return false;

};

Эта функция корректно ведет себя при компиляции Win32 версии и дает сбой при сборке в
режиме Win64. Рассмотрим пример использования функции:

#ifdef IS_64

    const char WinXX[] = "Win64";

#else

    const char WinXX[] = "Win32";

#endif

int _tmain(int argc, _TCHAR* argv[])

{
ArrayOfStrings array;

    array.push_back(string("123456"));

    array.push_back(string("QWERTY"));

    if (Find_Incorrect(array))

        printf("Find_Incorrect (%s): ERROR!n", WinXX);

    else

        printf("Find_Incorrect (%s): OK!n", WinXX);

    return 0;

}

Find_Incorrect (Win32): OK!

Find_Incorrect (Win64): ERROR!

Ошибка заключается в использовании типа unsigned для переменной "n", хотя функция find()
возвращает значение типа string::size_type. В 32-битной программе тип string::size_type и unsigned
совпадают, и мы получаем верный результат.

В 64-битной программе string::size_type и unsigned перестают совпадать. Так как подстрока не
находится, функция find() возвращает значение string::npos, которое равно
0xFFFFFFFFFFFFFFFFui64. Это значение урезается до величины 0xFFFFFFFFu и помещается в 32-
битную переменную. В результате условие 0xFFFFFFFFu == 0xFFFFFFFFFFFFFFFFui64 всегда false и
мы получаем сообщение "Find_Incorrect (Win64): ERROR!".

Исправим код, используя тип string::size_type.

bool Find_Correct(const ArrayOfStrings &arrStr)

{

    ArrayOfStrings::const_iterator it;

    for (it = arrStr.begin(); it != arrStr.end(); ++it)

    {

        string::size_type n = it->find("ABC");

        if (n != string::npos)

         return true;

    }

    return false;

};
Теперь код работает корректно, хотя постоянно писать тип string::size_type длинно и не красиво.
Можно переопределить его через typedef, но все равно это выглядит как-то сложно. Используя
C++0x, мы можем сделать код гораздо изящней надежней.

Для этого мы воспользуемся ключевым словом auto. Ранее auto означало, что переменная
создается на стеке, и подразумевалось неявно в случае, если вы не указали что-либо другое,
например register. Теперь тип переменной, объявленной как auto, определяется компилятором
самостоятельно на основе того, чем эта переменная инициализируется.

Следует заметить, что auto-переменная не сможет хранить значения разных типов в течение
одного запуска программы. Си++ остается статически типизированным языком, и указание auto
лишь говорит компилятору самостоятельно позаботиться об определении типа: после
инициализации сменить тип переменной будет уже нельзя.

Воспользуемся ключевым словом auto в нашем коде. Проект был создан в Visual Studio 2005, а
поддержка C++0x реализована только начиная с версии Visual Studio 2010. Поэтому для
компиляции я воспользовался компилятором Intel C++, входящим в состав Intel Parallel Studio 11.1
и поддерживающим стандарт C++0x. Поддержка C++0x включается в разделе Language и носит
название "Enable C++0x Support". Как видно из рисунка 1, эта опция является Intel Specific.




Рисунок 1 - Поддержка стандарта C++0x

Модифицированный код выглядит следующим образом:

bool Find_Cpp0X(const ArrayOfStrings &arrStr)

{

    for (auto it = arrStr.begin(); it != arrStr.end(); ++it)
{

        auto n = it->find("ABC");

        if (n != string::npos)

         return true;

    }

    return false;

};

Обратите внимание, как теперь объявлена переменная "n". Неправда ли, элегантно и устраняет от
ряд ошибок, в том числе и 64-битных. Переменная "n" будет иметь ровно тот тип, который
возвращает функция find(), то-есть string::size_type. Также обратите внимание, что исчезла строчка
объявления итератора:

ArrayOfStrings::const_iterator it;

Объявлять переменную it внутри цикла было некрасиво (длинно). И поэтому объявление было
вынесено отдельно. Теперь проблемы длины нет:

for (auto it = arrStr.begin(); ......)

Рассмотрим еще одно ключевое слово - decltype. Оно позволяет задать тип на основании типа
другой переменной. Если бы в нашем коде, мы должны были объявить все переменные заранее,
то можно было бы написать так:

bool Find_Cpp0X_2(const ArrayOfStrings &arrStr)

{

    decltype(arrStr.begin()) it;

    decltype(it->find("")) n;

    for (it = arrStr.begin(); it != arrStr.end(); ++it)

    {

        n = it->find("ABC");

        if (n != string::npos)

         return true;

    }

    return false;

};

Конечно, в данном случае это бессмысленно, но может быть весьма удобно во многих ситуациях.
К сожалению (или к счастью для нас :-), хотя новый стандарт облегчает написание безопасного 64-
битного кода, он не помогает в устранении уже существующих дефектов. Для того чтобы
использовать memsize-тип или auto для устранений ошибки, эту ошибку нужно в начале
обнаружить. Следовательно, актуальность использования инструмента Viva64 с приходом
стандарта C++0x не изменится.

P.S.
Проект с кодом можно скачать здесь.

More Related Content

PDF
Статический анализ Си++ кода и новый стандарт языка C++0x
Tatyanazaxarova
 
PDF
Красивая 64-битная ошибка на языке Си
Tatyanazaxarova
 
PDF
Оптимизация в мире 64-битных ошибок
Tatyanazaxarova
 
PDF
Урок 17. Паттерн 9. Смешанная арифметика
Tatyanazaxarova
 
PPT
практика 7
student_kai
 
PDF
Урок 11. Паттерн 3. Операции сдвига
Tatyanazaxarova
 
PDF
Урок 21. Паттерн 13. Выравнивание данных
Tatyanazaxarova
 
Статический анализ Си++ кода и новый стандарт языка C++0x
Tatyanazaxarova
 
Красивая 64-битная ошибка на языке Си
Tatyanazaxarova
 
Оптимизация в мире 64-битных ошибок
Tatyanazaxarova
 
Урок 17. Паттерн 9. Смешанная арифметика
Tatyanazaxarova
 
практика 7
student_kai
 
Урок 11. Паттерн 3. Операции сдвига
Tatyanazaxarova
 
Урок 21. Паттерн 13. Выравнивание данных
Tatyanazaxarova
 

What's hot (20)

PPTX
стандартная библиотека с++: введение
mcroitor
 
PPTX
Статический и динамический полиморфизм в C++, Дмитрий Леванов
Yandex
 
PPTX
Статический и динамический полиморфизм в C++, Дмитрий Леванов
Yandex
 
PDF
Урок 13. Паттерн 5. Адресная арифметика
Tatyanazaxarova
 
PPTX
Cpp/cli particularities
mcroitor
 
PPTX
особенности программирования на с++
mcroitor
 
PDF
Rust: абстракции и безопасность, совершенно бесплатно
Open-IT
 
PPTX
Cpp/cli types
mcroitor
 
PPTX
указатель на функцию
Aleksandr Pavlenko
 
PDF
5.4 Ключевые слова static и inline
DEVTYPE
 
PPTX
контейнеры STL
mcroitor
 
PDF
359.краткое введение в систему octave
ivanov1566359955
 
PDF
5.1 Перегрузка операторов
DEVTYPE
 
PDF
Урок 9. Паттерн 1. Магические числа
Tatyanazaxarova
 
PPTX
Javascript functions
Alexey Bovanenko
 
PPTX
алгоритмы stl
mcroitor
 
PPSX
scanf(). Операторы ветвления. Тернарный оператор. switch
Ihor Porotikov
 
PPTX
указатель на указатель 1
Aleksandr Pavlenko
 
ODP
Assert c
Alexey Bovanenko
 
PDF
2.6 Динамическая память
DEVTYPE
 
стандартная библиотека с++: введение
mcroitor
 
Статический и динамический полиморфизм в C++, Дмитрий Леванов
Yandex
 
Статический и динамический полиморфизм в C++, Дмитрий Леванов
Yandex
 
Урок 13. Паттерн 5. Адресная арифметика
Tatyanazaxarova
 
Cpp/cli particularities
mcroitor
 
особенности программирования на с++
mcroitor
 
Rust: абстракции и безопасность, совершенно бесплатно
Open-IT
 
Cpp/cli types
mcroitor
 
указатель на функцию
Aleksandr Pavlenko
 
5.4 Ключевые слова static и inline
DEVTYPE
 
контейнеры STL
mcroitor
 
359.краткое введение в систему octave
ivanov1566359955
 
5.1 Перегрузка операторов
DEVTYPE
 
Урок 9. Паттерн 1. Магические числа
Tatyanazaxarova
 
Javascript functions
Alexey Bovanenko
 
алгоритмы stl
mcroitor
 
scanf(). Операторы ветвления. Тернарный оператор. switch
Ihor Porotikov
 
указатель на указатель 1
Aleksandr Pavlenko
 
2.6 Динамическая память
DEVTYPE
 
Ad

Similar to Как стандарт C++0x поможет в борьбе с 64-битными ошибками (20)

PDF
Урок 5. Сборка 64-битного приложения
Tatyanazaxarova
 
PDF
Разработка статического анализатора кода для обнаружения ошибок переноса прог...
Tatyanazaxarova
 
PPTX
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Platonov Sergey
 
PDF
Правила статического анализа кода для диагностики потенциально опасных констр...
Sergey Vasilyev
 
PPTX
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
Pavel Tsukanov
 
PDF
Коллекция примеров 64-битных ошибок в реальных программах
Tatyanazaxarova
 
PDF
Урок 26. Оптимизация 64-битных программ
Tatyanazaxarova
 
PDF
Что такое size_t и ptrdiff_t
Tatyanazaxarova
 
PPTX
Принципы работы статического анализатора кода PVS-Studio
Andrey Karpov
 
PDF
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Tatyanazaxarova
 
PDF
Использование библиотеки анализа кода OpenC++: модификация, улучшение, исправ...
Tatyanazaxarova
 
PDF
Большой брат помогает тебе
Tatyanazaxarova
 
PPTX
Павел Беликов, Как избежать ошибок, используя современный C++
Sergey Platonov
 
PDF
20 ловушек переноса Си++ - кода на 64-битную платформу
Tatyanazaxarova
 
PDF
Урок 15. Паттерн 7. Упаковка указателей
Tatyanazaxarova
 
PDF
Особенности разработки 64-битных приложений
Tatyanazaxarova
 
PDF
64-битный конь, который умеет считать
Tatyanazaxarova
 
PPTX
Паттерны 64-битных ошибок в играх
Andrey Karpov
 
PPTX
статический анализ кода
Andrey Karpov
 
PPTX
Статический анализ кода
Pavel Tsukanov
 
Урок 5. Сборка 64-битного приложения
Tatyanazaxarova
 
Разработка статического анализатора кода для обнаружения ошибок переноса прог...
Tatyanazaxarova
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Platonov Sergey
 
Правила статического анализа кода для диагностики потенциально опасных констр...
Sergey Vasilyev
 
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
Pavel Tsukanov
 
Коллекция примеров 64-битных ошибок в реальных программах
Tatyanazaxarova
 
Урок 26. Оптимизация 64-битных программ
Tatyanazaxarova
 
Что такое size_t и ptrdiff_t
Tatyanazaxarova
 
Принципы работы статического анализатора кода PVS-Studio
Andrey Karpov
 
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Tatyanazaxarova
 
Использование библиотеки анализа кода OpenC++: модификация, улучшение, исправ...
Tatyanazaxarova
 
Большой брат помогает тебе
Tatyanazaxarova
 
Павел Беликов, Как избежать ошибок, используя современный C++
Sergey Platonov
 
20 ловушек переноса Си++ - кода на 64-битную платформу
Tatyanazaxarova
 
Урок 15. Паттерн 7. Упаковка указателей
Tatyanazaxarova
 
Особенности разработки 64-битных приложений
Tatyanazaxarova
 
64-битный конь, который умеет считать
Tatyanazaxarova
 
Паттерны 64-битных ошибок в играх
Andrey Karpov
 
статический анализ кода
Andrey Karpov
 
Статический анализ кода
Pavel Tsukanov
 
Ad

More from Tatyanazaxarova (20)

PDF
Урок 27. Особенности создания инсталляторов для 64-битного окружения
Tatyanazaxarova
 
PDF
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Tatyanazaxarova
 
PDF
Урок 24. Фантомные ошибки
Tatyanazaxarova
 
PDF
Урок 23. Паттерн 15. Рост размеров структур
Tatyanazaxarova
 
PDF
Урок 20. Паттерн 12. Исключения
Tatyanazaxarova
 
PDF
Урок 19. Паттерн 11. Сериализация и обмен данными
Tatyanazaxarova
 
PDF
Урок 16. Паттерн 8. Memsize-типы в объединениях
Tatyanazaxarova
 
PDF
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Tatyanazaxarova
 
PDF
Урок 8. Статический анализ для выявления 64-битных ошибок
Tatyanazaxarova
 
PDF
Урок 7. Проблемы выявления 64-битных ошибок
Tatyanazaxarova
 
PDF
Урок 6. Ошибки в 64-битном коде
Tatyanazaxarova
 
PDF
Урок 4. Создание 64-битной конфигурации
Tatyanazaxarova
 
PPTX
PVS-Studio, решение для разработки современных ресурсоемких приложений
Tatyanazaxarova
 
PPTX
Статический анализ Си++ кода
Tatyanazaxarova
 
PDF
PVS-Studio
Tatyanazaxarova
 
PDF
PVS-Studio научился следить за тем, как вы программируете
Tatyanazaxarova
 
PDF
Пояснения к статье про Copy-Paste
Tatyanazaxarova
 
PDF
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Tatyanazaxarova
 
PDF
Статический анализ и ROI
Tatyanazaxarova
 
PDF
Вечный вопрос измерения времени
Tatyanazaxarova
 
Урок 27. Особенности создания инсталляторов для 64-битного окружения
Tatyanazaxarova
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Tatyanazaxarova
 
Урок 24. Фантомные ошибки
Tatyanazaxarova
 
Урок 23. Паттерн 15. Рост размеров структур
Tatyanazaxarova
 
Урок 20. Паттерн 12. Исключения
Tatyanazaxarova
 
Урок 19. Паттерн 11. Сериализация и обмен данными
Tatyanazaxarova
 
Урок 16. Паттерн 8. Memsize-типы в объединениях
Tatyanazaxarova
 
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Tatyanazaxarova
 
Урок 8. Статический анализ для выявления 64-битных ошибок
Tatyanazaxarova
 
Урок 7. Проблемы выявления 64-битных ошибок
Tatyanazaxarova
 
Урок 6. Ошибки в 64-битном коде
Tatyanazaxarova
 
Урок 4. Создание 64-битной конфигурации
Tatyanazaxarova
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
Tatyanazaxarova
 
Статический анализ Си++ кода
Tatyanazaxarova
 
PVS-Studio
Tatyanazaxarova
 
PVS-Studio научился следить за тем, как вы программируете
Tatyanazaxarova
 
Пояснения к статье про Copy-Paste
Tatyanazaxarova
 
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Tatyanazaxarova
 
Статический анализ и ROI
Tatyanazaxarova
 
Вечный вопрос измерения времени
Tatyanazaxarova
 

Как стандарт C++0x поможет в борьбе с 64-битными ошибками

  • 1. Как стандарт C++0x поможет в борьбе с 64-битными ошибками Автор: Андрей Карпов Дата: 28.02.2010 Программисты видят в стандарте C++0x возможность использовать лямбда-функции и прочие мало понятные для меня сущности :). Я увидел в нем удобные средства, позволяющие исключить многие 64-битные ошибки. Рассмотрим функцию, которая возвращает true, если хотя бы в одной из строк встречается последовательность "ABC". typedef vector<string> ArrayOfStrings; bool Find_Incorrect(const ArrayOfStrings &arrStr) { ArrayOfStrings::const_iterator it; for (it = arrStr.begin(); it != arrStr.end(); ++it) { unsigned n = it->find("ABC"); if (n != string::npos) return true; } return false; }; Эта функция корректно ведет себя при компиляции Win32 версии и дает сбой при сборке в режиме Win64. Рассмотрим пример использования функции: #ifdef IS_64 const char WinXX[] = "Win64"; #else const char WinXX[] = "Win32"; #endif int _tmain(int argc, _TCHAR* argv[]) {
  • 2. ArrayOfStrings array; array.push_back(string("123456")); array.push_back(string("QWERTY")); if (Find_Incorrect(array)) printf("Find_Incorrect (%s): ERROR!n", WinXX); else printf("Find_Incorrect (%s): OK!n", WinXX); return 0; } Find_Incorrect (Win32): OK! Find_Incorrect (Win64): ERROR! Ошибка заключается в использовании типа unsigned для переменной "n", хотя функция find() возвращает значение типа string::size_type. В 32-битной программе тип string::size_type и unsigned совпадают, и мы получаем верный результат. В 64-битной программе string::size_type и unsigned перестают совпадать. Так как подстрока не находится, функция find() возвращает значение string::npos, которое равно 0xFFFFFFFFFFFFFFFFui64. Это значение урезается до величины 0xFFFFFFFFu и помещается в 32- битную переменную. В результате условие 0xFFFFFFFFu == 0xFFFFFFFFFFFFFFFFui64 всегда false и мы получаем сообщение "Find_Incorrect (Win64): ERROR!". Исправим код, используя тип string::size_type. bool Find_Correct(const ArrayOfStrings &arrStr) { ArrayOfStrings::const_iterator it; for (it = arrStr.begin(); it != arrStr.end(); ++it) { string::size_type n = it->find("ABC"); if (n != string::npos) return true; } return false; };
  • 3. Теперь код работает корректно, хотя постоянно писать тип string::size_type длинно и не красиво. Можно переопределить его через typedef, но все равно это выглядит как-то сложно. Используя C++0x, мы можем сделать код гораздо изящней надежней. Для этого мы воспользуемся ключевым словом auto. Ранее auto означало, что переменная создается на стеке, и подразумевалось неявно в случае, если вы не указали что-либо другое, например register. Теперь тип переменной, объявленной как auto, определяется компилятором самостоятельно на основе того, чем эта переменная инициализируется. Следует заметить, что auto-переменная не сможет хранить значения разных типов в течение одного запуска программы. Си++ остается статически типизированным языком, и указание auto лишь говорит компилятору самостоятельно позаботиться об определении типа: после инициализации сменить тип переменной будет уже нельзя. Воспользуемся ключевым словом auto в нашем коде. Проект был создан в Visual Studio 2005, а поддержка C++0x реализована только начиная с версии Visual Studio 2010. Поэтому для компиляции я воспользовался компилятором Intel C++, входящим в состав Intel Parallel Studio 11.1 и поддерживающим стандарт C++0x. Поддержка C++0x включается в разделе Language и носит название "Enable C++0x Support". Как видно из рисунка 1, эта опция является Intel Specific. Рисунок 1 - Поддержка стандарта C++0x Модифицированный код выглядит следующим образом: bool Find_Cpp0X(const ArrayOfStrings &arrStr) { for (auto it = arrStr.begin(); it != arrStr.end(); ++it)
  • 4. { auto n = it->find("ABC"); if (n != string::npos) return true; } return false; }; Обратите внимание, как теперь объявлена переменная "n". Неправда ли, элегантно и устраняет от ряд ошибок, в том числе и 64-битных. Переменная "n" будет иметь ровно тот тип, который возвращает функция find(), то-есть string::size_type. Также обратите внимание, что исчезла строчка объявления итератора: ArrayOfStrings::const_iterator it; Объявлять переменную it внутри цикла было некрасиво (длинно). И поэтому объявление было вынесено отдельно. Теперь проблемы длины нет: for (auto it = arrStr.begin(); ......) Рассмотрим еще одно ключевое слово - decltype. Оно позволяет задать тип на основании типа другой переменной. Если бы в нашем коде, мы должны были объявить все переменные заранее, то можно было бы написать так: bool Find_Cpp0X_2(const ArrayOfStrings &arrStr) { decltype(arrStr.begin()) it; decltype(it->find("")) n; for (it = arrStr.begin(); it != arrStr.end(); ++it) { n = it->find("ABC"); if (n != string::npos) return true; } return false; }; Конечно, в данном случае это бессмысленно, но может быть весьма удобно во многих ситуациях.
  • 5. К сожалению (или к счастью для нас :-), хотя новый стандарт облегчает написание безопасного 64- битного кода, он не помогает в устранении уже существующих дефектов. Для того чтобы использовать memsize-тип или auto для устранений ошибки, эту ошибку нужно в начале обнаружить. Следовательно, актуальность использования инструмента Viva64 с приходом стандарта C++0x не изменится. P.S. Проект с кодом можно скачать здесь.