Обычно каждое выражение в C, включая часть выражения внутри другого выражения, имеет тип. Для идентификаторов объявляется тип. Для констант или литералов тип является следствием формы и значения константы или литерала. Для результатов операторов тип определяется типами операндов и правилами для оператора.
Например, для целочисленных констант есть таблица в C 2018 6.4.4.1 5. Для десятичные константы без суффикса (например, l
для long
), он говорит, что тип является первым из int
, long int
и long long int
, который может представлять значение. В следующем абзаце также говорится, что, если значение не соответствует ни одному из них, оно может соответствовать некоторому расширенному целочисленному типу, предоставленному реализацией C. Он также говорит, что значение не может быть представлено каким-либо типом в своем списке, и оно «не имеет типа». Если константа не имеет типа, то программа нарушает ограничение в разделе ограничений 6.4.4 2, в котором говорится: «Каждая константа должна иметь тип…», и поведение не определяется стандартом C. Когда программа нарушает ограничение, указанное в разделе ограничений, компилятор должен выдать для этого сообщение диагностики c.
Для многих операторов правила говорят, что целочисленные операнды продвигаются на ширину не менее int
. (Есть некоторые технические особенности, которые я здесь опускаю, но это основной эффект целочисленных рекламных акций.) Это означает, что вы не можете выполнять арифметические операции c на только a char
или short
, где в реализация C, в которой эти типы уже, чем int
. Кроме того, для многих операторов с двумя операндами операнды преобразуются в некоторый общий тип, как правило, в «больший» тип (хотя, опять же, есть некоторые технические особенности, которые могут быть более проблематичными из-за преобразований между знаковыми и беззнаковыми типами).
Все эти правила о типах влияют на значения , которые будут получены в результате вычисления выражений. Если вы добавите какое-то значение типа X к некоторому значению типа Y и умножите на какое-то значение типа Z , правила будут применяться для определения того, какое значение полученные результаты. Но в правилах не сказано, как должно быть представлено значение, пока программа работает с выражением. Компилятор может сгенерировать код, который обрабатывает значения в регистрах, который сохраняет некоторые константы в непосредственных полях инструкций, который создает некоторые константы на лету во время выполнения программы, который не содержит фактических инструкций, выполняющих явные операции, поскольку компилятор оптимизировал выражение для другая форма и многое другое. Стандарт C требует, чтобы значение было представлено только определенным образом, когда оно хранится в объекте (память зарезервирована для хранения значения, как в случае определения переменной). (И даже это можно удалить путем оптимизации, если программа ведет себя таким же образом в отношении наблюдаемых эффектов, как определено стандартом C.)