SlideShare a Scribd company logo
Почему A + B != A - (-B)
Автор: Андрей Карпов

Дата: 21.12.2009

Разрабатывая анализатор Viva64, предназначенный для поиска 64-битных ошибок, я иногда
сталкиваюсь с интересными моментами поведения кода. Хочу показать один пример, который с
практической точки зрения не очень интересен, но может быть полезен для понимания более
сложных случаев.

char *A = "123456789";

unsigned B = 1;

char *X = A + B; // X: "23456789"

char *Y = A - (-B); // Y: <Bad Ptr>

Если мы скомпилируем 32-битный вариант кода, то выражения "A + B" и "A - (-B)" будут
эквивалентны. В 32-битном коде указатели X и Y будут указывать на второй элемент массива A.
Для лучшего понимания процесс вычисления "A - (-B)" показан на рисунке 1.




Рисунок 1 - Выражение "A - (-B)" в 32-битной программе

А вот в при компиляции 64-битного кода выражения "A + B" и "A - (-B)" будут обозначать
совершенно разное. Подвыражение "-B" будет иметь беззнаковый тип и равняться 0xFFFFFFFFu. И
именно это значение 0xFFFFFFFFu будет вычтено из указателя (смотри также рисунок 2).
Рисунок 2 - Выражение "A - (-B)" в 64-битной программе

Приведенная ошибка приводит к доступу за границы массива на 64-битной системе. Проявление
подобных ошибок можно ожидать при работе с отрицательными индексами, когда для их
хранения используются 32-битные беззнаковые переменные. Пример:

unsigned Index = -1;

Array[Index] = Z;

Как и в предыдущем случае, выражение "Array[Index] = Z;" работоспособно в 32-битной
программе и приводит к ошибке в 64-битной.

Вывод:

Следует избегать использования беззнаковых типов данных для хранения отрицательных
значений. Если переменные, используемые для доступа к элементам массива, могут принимать
отрицательные значения, используйте только знаковые типы данных, например "int". Еще лучше
использовать такие типы как size_t и ptrdfiff_t.

More Related Content

What's hot

Программирование линейных алгоритмов
Программирование линейных алгоритмовПрограммирование линейных алгоритмов
Программирование линейных алгоритмов
Andrey Dolinin
 
Системы счисления
Системы счисленияСистемы счисления
Системы счисления
Andrey Dolinin
 
слайды к лекции №22
слайды к лекции №22слайды к лекции №22
слайды к лекции №22student_kai
 
3.7 Конструктор копирования и оператор присваивания
3.7 Конструктор копирования и оператор присваивания3.7 Конструктор копирования и оператор присваивания
3.7 Конструктор копирования и оператор присваивания
DEVTYPE
 
8 3-3
8 3-38 3-3
контрольная работа Variant i
контрольная работа Variant iконтрольная работа Variant i
контрольная работа Variant ileshiy_AlisA
 
Алгоритмическая конструкция Повторение
Алгоритмическая конструкция ПовторениеАлгоритмическая конструкция Повторение
Алгоритмическая конструкция Повторение
Andrey Dolinin
 

What's hot (7)

Программирование линейных алгоритмов
Программирование линейных алгоритмовПрограммирование линейных алгоритмов
Программирование линейных алгоритмов
 
Системы счисления
Системы счисленияСистемы счисления
Системы счисления
 
слайды к лекции №22
слайды к лекции №22слайды к лекции №22
слайды к лекции №22
 
3.7 Конструктор копирования и оператор присваивания
3.7 Конструктор копирования и оператор присваивания3.7 Конструктор копирования и оператор присваивания
3.7 Конструктор копирования и оператор присваивания
 
8 3-3
8 3-38 3-3
8 3-3
 
контрольная работа Variant i
контрольная работа Variant iконтрольная работа Variant i
контрольная работа Variant i
 
Алгоритмическая конструкция Повторение
Алгоритмическая конструкция ПовторениеАлгоритмическая конструкция Повторение
Алгоритмическая конструкция Повторение
 

More from Tatyanazaxarova

Урок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окруженияУрок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окружения
Tatyanazaxarova
 
Урок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программУрок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программ
Tatyanazaxarova
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокУрок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Tatyanazaxarova
 
Урок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиУрок 24. Фантомные ошибки
Урок 24. Фантомные ошибки
Tatyanazaxarova
 
Урок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структурУрок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структур
Tatyanazaxarova
 
Урок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данныхУрок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данных
Tatyanazaxarova
 
Урок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. ИсключенияУрок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. Исключения
Tatyanazaxarova
 
Урок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен даннымиУрок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен данными
Tatyanazaxarova
 
Урок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметикаУрок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметика
Tatyanazaxarova
 
Урок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединенияхУрок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединениях
Tatyanazaxarova
 
Урок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателейУрок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателей
Tatyanazaxarova
 
Урок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметикаУрок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметика
Tatyanazaxarova
 
Урок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвигаУрок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвига
Tatyanazaxarova
 
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументовУрок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Tatyanazaxarova
 
Урок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаУрок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числа
Tatyanazaxarova
 
Урок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибокУрок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибок
Tatyanazaxarova
 
Урок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокУрок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибок
Tatyanazaxarova
 
Урок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном кодеУрок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном коде
Tatyanazaxarova
 
Урок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложенияУрок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложения
Tatyanazaxarova
 
Урок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурацииУрок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурации
Tatyanazaxarova
 

More from Tatyanazaxarova (20)

Урок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окруженияУрок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окружения
 
Урок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программУрок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программ
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокУрок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
 
Урок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиУрок 24. Фантомные ошибки
Урок 24. Фантомные ошибки
 
Урок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структурУрок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структур
 
Урок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данныхУрок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данных
 
Урок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. ИсключенияУрок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. Исключения
 
Урок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен даннымиУрок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен данными
 
Урок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметикаУрок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметика
 
Урок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединенияхУрок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединениях
 
Урок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателейУрок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателей
 
Урок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметикаУрок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметика
 
Урок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвигаУрок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвига
 
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументовУрок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
 
Урок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаУрок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числа
 
Урок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибокУрок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибок
 
Урок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокУрок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибок
 
Урок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном кодеУрок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном коде
 
Урок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложенияУрок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложения
 
Урок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурацииУрок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурации
 

Почему A + B != A - (-B)

  • 1. Почему A + B != A - (-B) Автор: Андрей Карпов Дата: 21.12.2009 Разрабатывая анализатор Viva64, предназначенный для поиска 64-битных ошибок, я иногда сталкиваюсь с интересными моментами поведения кода. Хочу показать один пример, который с практической точки зрения не очень интересен, но может быть полезен для понимания более сложных случаев. char *A = "123456789"; unsigned B = 1; char *X = A + B; // X: "23456789" char *Y = A - (-B); // Y: <Bad Ptr> Если мы скомпилируем 32-битный вариант кода, то выражения "A + B" и "A - (-B)" будут эквивалентны. В 32-битном коде указатели X и Y будут указывать на второй элемент массива A. Для лучшего понимания процесс вычисления "A - (-B)" показан на рисунке 1. Рисунок 1 - Выражение "A - (-B)" в 32-битной программе А вот в при компиляции 64-битного кода выражения "A + B" и "A - (-B)" будут обозначать совершенно разное. Подвыражение "-B" будет иметь беззнаковый тип и равняться 0xFFFFFFFFu. И именно это значение 0xFFFFFFFFu будет вычтено из указателя (смотри также рисунок 2).
  • 2. Рисунок 2 - Выражение "A - (-B)" в 64-битной программе Приведенная ошибка приводит к доступу за границы массива на 64-битной системе. Проявление подобных ошибок можно ожидать при работе с отрицательными индексами, когда для их хранения используются 32-битные беззнаковые переменные. Пример: unsigned Index = -1; Array[Index] = Z; Как и в предыдущем случае, выражение "Array[Index] = Z;" работоспособно в 32-битной программе и приводит к ошибке в 64-битной. Вывод: Следует избегать использования беззнаковых типов данных для хранения отрицательных значений. Если переменные, используемые для доступа к элементам массива, могут принимать отрицательные значения, используйте только знаковые типы данных, например "int". Еще лучше использовать такие типы как size_t и ptrdfiff_t.