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

What's hot (20)

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

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

PDF
Урок 24. Фантомные ошибки
PDF
Урок 5. Сборка 64-битного приложения
PDF
Коллекция примеров 64-битных ошибок в реальных программах
PDF
Что такое size_t и ptrdiff_t
PDF
Статический анализ и регулярные выражения
PDF
Статический анализ исходного кода на примере WinMerge
PDF
64-битный конь, который умеет считать
PDF
Большой брат помогает тебе
PDF
Разработка статического анализатора кода для обнаружения ошибок переноса прог...
PPTX
Принципы работы статического анализатора кода PVS-Studio
PDF
Step cpp0201
PDF
20 ловушек переноса Си++ - кода на 64-битную платформу
PPTX
PVS-Studio, решение для разработки современных ресурсоемких приложений
PDF
Разница в подходах анализа кода компилятором и выделенным инструментом
PPT
паскаль 10кл 14
PPTX
Статический анализ кода
PPTX
статический анализ кода
PPTX
PVS-Studio, решение для разработки современных ресурсоемких приложений
PDF
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
PDF
Intel IPP Samples for Windows - работа над ошибками
Урок 24. Фантомные ошибки
Урок 5. Сборка 64-битного приложения
Коллекция примеров 64-битных ошибок в реальных программах
Что такое size_t и ptrdiff_t
Статический анализ и регулярные выражения
Статический анализ исходного кода на примере WinMerge
64-битный конь, который умеет считать
Большой брат помогает тебе
Разработка статического анализатора кода для обнаружения ошибок переноса прог...
Принципы работы статического анализатора кода PVS-Studio
Step cpp0201
20 ловушек переноса Си++ - кода на 64-битную платформу
PVS-Studio, решение для разработки современных ресурсоемких приложений
Разница в подходах анализа кода компилятором и выделенным инструментом
паскаль 10кл 14
Статический анализ кода
статический анализ кода
PVS-Studio, решение для разработки современных ресурсоемких приложений
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Intel IPP Samples for Windows - работа над ошибками
Ad

More from Tatyanazaxarova (20)

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

Как стандарт 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. Проект с кодом можно скачать здесь.