Преобразование типа данных с расширением знака вызывает неожиданное поведение
Этот дефект происходит, когда вы преобразуете со знаком или плоскость 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
- К - 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