ПрограммированиеC разработчик

Какие правила преобразования типов (type conversion, type promotion) применяются в выражениях в языке C? Приведите примеры неожиданных ошибок и решений.

Проходите собеседования с ИИ помощником Hintsage

Ответ

В языке C в выражениях часто происходят преобразования типов (type promotion, type conversion), регулируемые стандартом:

  • Integer Promotion: типы меньшей разрядности (например, char, short) автоматически преобразуются к int или unsigned int перед арифметическими операциями.
  • Usual Arithmetic Conversions: если операнды разных типов — преобразуются к "более широкому" типу согласно заданным правилам.
  • При смешанных операциях со знаковыми и беззнаковыми типами результат может неожиданно измениться из-за преобразования.

Пример:

unsigned short a = 65535; signed short b = -1; printf("%d ", a + b); // зависит от преобразования!

Рекомендация: внимательно следите за типами операндов, особенно при работе с битовыми операциями, длинами массивов, индексами, и избегайте неявного смешивания знаковых и беззнаковых типов.

Вопрос с подвохом

Что выведет следующий фрагмент?

unsigned int u = 1; int i = -2; printf("%d ", u + i);

Ответ: Переменная i будет преобразована к unsigned int, итоговое значение станет очень большим, т.к. результат под капотом: 1U + (unsigned int)-2U, что даст число, близкое к UINT_MAX (4294967295). Будет напечатано отрицательное число только если printf форматировать как int, иначе мусор.

Примеры реальных ошибок из-за незнания тонкостей темы


История

В вычислении средних значений интенсивности изображения перепутали int и unsigned int. Отрицательные значения неверно транслировались через unsigned и давали гигантские числа, приводя к переполнению буфера изображения.


История

Во встроенной прошивке считали длину строки через size_t, а индексировали массив через int. На проверке условия выхода за пределы массива сравнивали int i >= size_t len, что ломало логику для длинных строк и вызывало баги при сравнении разных типов (size_t — unsigned).


История

Разработчик на финансовом проекте вычислял остаток деления для отрицательных чисел через %, забывая, что знак результата для отрицательных операндов зависит от реализации. В одном окружении результат был положительный, в другом — отрицательный, отчего расчёты периодически "съезжали".