Преобразование типа данных с расширением знака вызывает неожиданное поведение
Неправильное употребление значения расширенного символа знака происходит, когда вы преобразовываете или простую переменную char
со знаком, содержащую возможные отрицательные величины к более широкому целочисленному типу данных (или выполните арифметическую операцию, которая делает преобразование), и затем используйте получившееся значение одним из этих способов:
Для сравнения с EOF
(использующий ==
или !=
)
Как индекс массива
В качестве аргумента к обрабатывающей символ функции в ctype.h
, например, isalpha()
или isdigit()
Если вы преобразовываете переменную char
со знаком с отрицательной величиной к более широкому типу, такому как int
, знаковый бит сохраняется (расширение знака). Это может привести к определенным проблемам даже в ситуациях, где вы думаете, что объяснили знаковый бит.
Например, значение char
со знаком-1 может представлять символьный EOF
(конец файла), который является недопустимым символом. Предположим переменная char
, var
получает это значение. Если вы обрабатываете var
как переменную char
, вы можете хотеть записать специальный код, чтобы составлять это значение недопустимого символа. Однако, если вы выполняете операцию, такую как var++
(включающее целочисленное продвижение), это приводит к значению 0, который представляет допустимое значение '\0'
случайно. Вы перешли от недопустимого до допустимого значения через арифметическую операцию.
Даже для отрицательных величин кроме-1, преобразование от char
со знаком до int
со знаком может привести к другим проблемам. Например, значение char
со знаком-126 эквивалентно значению unsigned char
130 (соответствие расширенному символу '\202'
). Если вы преобразовываете значение от char
до int
, знаковый бит сохраняется. Если вы затем бросаете получившееся значение к unsigned int
, вы получаете неожиданно большое значение, 4294967170 (принятие 32-битного int
). Если ваш код ожидает значение unsigned char
130 в итоговой переменной unsigned int
, вы видите неожиданные результаты.
Первопричиной этой проблемы является расширение знака во время преобразования в более широкий тип. Большая часть архитектуры использует дополнительное представление two для хранения значений. В этом представлении старший значащий бит указывает на знак значения. Когда преобразовано в более широкий тип, преобразование сделано путем копирования этого знакового бита во все ведущие биты более широкого типа, так, чтобы знак был сохранен. Например, значение char
-3 представлено как 11111101
(принимающий 8-битный char
). Когда преобразовано в int
, представление:
11111111 11111111 11111111 11111101
int
. Однако, когда преобразовано в unsigned int
, значение (4294967293) больше не является тем же самым как unsigned char
, эквивалентным из исходного значения char
. Если вы не знаете об этой проблеме, вы видите неожиданные результаты в своем коде.В следующих случаях Средство поиска Ошибки отмечает использование переменных после преобразования от char
до более широкого типа данных или арифметической операции, которая неявно преобразовывает переменную в более широкий тип данных:
Если вы сравниваете значение переменных с EOF:
Значение char
-1 может представлять недопустимый символ EOF
или допустимое значение расширенного символа '\377'
(соответствующий эквивалентному unsigned char
, 255). После того, как переменная char
брошена к более широкому типу, такому как int
из-за расширения знака, значение char
-1, представляя один из EOF
или '\377'
становится значением int
-1, представляя только EOF
. Значение unsigned char
255 больше не может восстанавливаться с переменной int
. Средство поиска ошибки отмечает эту ситуацию так, чтобы можно было бросить переменную к unsigned char
сначала (или избежать char
-to-int
преобразование или операция преобразования перед сравнением с EOF
). Только затем сравнение с EOF
значимо. Смотрите Значение Расширенного символа Знака По сравнению с EOF.
Если вы используете значение переменных в качестве индекса массива:
После того, как переменная char
брошена к более широкому типу, такому как int
из-за расширения знака, все отрицательные величины сохраняют свой знак. Если вы используете отрицательные величины непосредственно, чтобы получить доступ к массиву, вы вызываете переполнение буфера / потеря значимости. Даже когда вы объясняете отрицательные величины, способ, которым вы объясняете их, может привести к неправильным элементам, считанным из массива. Смотрите Значение Расширенного символа Знака, Используемое в качестве Индекса массива.
Если вы передаете значение переменных в качестве аргумента к обрабатывающей символ функции:
Согласно стандарту C11 (Раздел 7.4), если вы предоставляете целочисленный аргумент, который не может быть представлен как unsigned char
или EOF
, получившееся поведение не определено. Средство поиска ошибки отмечает эту ситуацию, потому что отрицательные значения char
после преобразования больше не могут представляться как unsigned char
или EOF
. Например, значение char
со знаком-126 эквивалентно значению unsigned char
130, но значение int
со знаком-126 не может быть представлено как unsigned char
или EOF
.
Перед преобразованием в более широкий целочисленный тип данных, бросок со знаком или плоскость значение char
явным образом к unsigned char
.
Если вы используете тип данных char
, чтобы не представлять символы, но просто как меньший тип данных, чтобы сохранить память, ваше использование расширенных знаком значений char
может избежать рисков, упомянутых ранее. Если так, добавьте комментарии в свой результат или код, чтобы избежать другого анализа. Смотрите Результаты Polyspace Адреса Через Исправления ошибок или Комментарии.
Группа: Программирование |
Язык: C | C++ |
Значение по умолчанию: на |
Синтаксис командной строки: CHARACTER_MISUSE |
Влияние: носитель |
ID CWE: 704 |
Character value absorbed into EOF
| Errno not checked
| Find defects (-checkers)
| Invalid use of standard library integer routine
| Returned value of a sensitive function not checked