Тип a ? b : c
не зависит от a
. Это безоговорочно определяется типами b
и c
. Полные правила сложны, но для арифметических операндов тип определяется обычными арифметическими преобразованиями. По сути, два операнда преобразуются в общий тип. Для int
и unsigned int
результирующий тип будет unsigned int
.
Условный оператор ? :
описан в п. 6.5.15 стандарта C 2018. В параграфе 4 говорится, что результат «конвертируется в тип, описанный ниже».
Пункт 5 описывает результат для арифметических типов, структур и объединений:
Если и второй, и третий операнды имеют арифметический тип, тип результата будет тип результата, который будет определен обычными арифметическими преобразованиями, если бы они применялись к этим двум операндам. Если оба операнда имеют структуру или тип объединения, результат имеет этот тип. Если оба операнда имеют тип void, результат имеет тип void.
Арифметические типы - это целочисленные типы и типы с плавающей запятой, согласно 6.2.5 18. (К ним относятся как действительные, так и комплексные типы.) Обычные арифметические преобразования описаны в 6.3.1.8 1, которые (в моем резюме не цитируются) ):
- Если любой из них является сложным типом, результат сложный, а остальные правила описывают тип действительной и мнимой частей. В противном случае результат действителен, а остальные правила описывают его тип.
- Если значение равно
long double
, результат равен long double
.
- В противном случае, если любой из них равен
double
, результат равен double
.
- В противном случае, если значение равно
float
, результат будет float
.
- В противном случае целочисленные преобразования применяются к каждому операнду (они указаны в 6.3.1.1 2), а затем оба типа преобразуются в общий целочисленный тип. Полные правила для этого несколько сложны, используют концепцию ранга, которая требует некоторого объяснения, и охватывают некоторые эзотерические ситуации, поэтому я просто суммирую их для нормальных ситуаций: если оба типа
int
или уже (то есть меньше бит или то же количество битов, но подписанных вместо беззнаковых), результат равен int
. В противном случае, если оба значения unsigned int
или уже, результатом будет unsigned int
. В противном случае результатом будет более широкий тип.
Правила структуры, объединения и пустоты понятны: оба операнда должны иметь одинаковый тип, и это результат.
Пункт 6 описывает результат для указателей:
Если второй и третий операнды являются указателями или один является константой нулевого указателя, а другой является указателем, тип результата является указателем на тип, квалифицированный всеми квалификаторами типов типов, на которые ссылаются оба операнда. Кроме того, если оба операнда являются указателями на совместимые типы или на версии с разными квалификациями совместимых типов, тип результата является указателем на версию с определенными квалификациями составного типа; если один операнд является константой нулевого указателя, результат имеет тип другого операнда; в противном случае один операнд является указателем на void или квалифицированной версией void , и в этом случае тип результата является указателем на соответствующую квалифицированную версию void .
В целом, это говорит:
- Если у любого операнда есть квалификаторы (
const
, volatile
, restrict
или _Atomic
), включите их в тип результата.
- Если два типа различны, но совместимы (например, массив неизвестного размера и массив известного размера, оба с элементами одного типа), объедините эти два типа. (Другие возможности объединения, помимо размера массива, включают элементы массивов, отличающихся друг от друга, но совместимых типов, функцию с и без списка параметров и параметры функций, являющиеся различными, но совместимыми типами.)