Ответ 1
OP спрашивает о прямой цитате из стандарта - N1570 §6.10.1p3,4 + примечание 168:
... выражение управляющей константы оценивается в соответствии с правилами 6.6.... Это включает в себя интерпретацию символьных констант, которые могут включать в себя преобразование управляющих последовательностей в исполнительные элементы набора символов. Является ли числовое значение для этих символьных констант совпадающим с значением, полученным, когда идентичная константа символа встречается в выражении (отличном от директивы #if или #elif), определяется реализацией. 168
[сноска 168] Таким образом, константное выражение в следующей директиве #if и инструкции if не гарантируется для оценки того же значения в этих двух контекстах.
#if 'z' - 'a' == 25 if ('z' - 'a' == 25)
Итак, да, это действительно не гарантировано.
Чтобы понять, почему это не гарантировано, сначала вам нужно знать, что стандарт C не требует, чтобы символьные константы 'a'
и 'z'
имели числовые значения, присвоенные этим символам ASCII. Большинство реализаций C в настоящее время используют ASCII или надмножество, но существует еще одна кодировка под названием EBCDIC, которая по-прежнему широко используется (только для мэйнфреймов IBM, но их все еще много). В EBCDIC не только 'a'
и 'z'
имеют разные значения из ASCII, а алфавит не является последовательной последовательностью! Поэтому выражение 'z' - 'a' == 25
может не оценивать истину в первую очередь.
Вам также необходимо знать, что стандарт C пытается поддерживать различие между текстовой кодировкой, используемой для исходного кода ( "набор исходных символов" ), и текстовым кодированием, которое программа будет использовать во время выполнения ( "набор символов выполнения" "). Это значит, что вы можете, по крайней мере в принципе, взять программу, источник которой закодирован в тексте ASCII и запустить ее без изменений на компьютере, использующем EBCDIC, просто путем кросс-компиляции соответствующим образом; вам не нужно сначала преобразовывать исходный текст в EBCDIC.
Теперь компилятор должен понимать оба набора символов, если они разные, но исторически, препроцессор C (этапы перевода с 1 по 4), а "собственный компилятор" (этапы с 5 по 7) были двумя отдельными программами, а выражения #if
- это единственное место, где препроцессор должен был знать о наборе символов выполнения. Таким образом, определив, соответствует ли установленный препроцессором "набор символов выполнения", который используется соответствующим компилятором, стандарт разрешает препроцессору выполнять всю свою работу в наборе исходных символов, что делает жизнь немного легче назад в 1989 году.
Сказав все это, я был бы очень удивлен, если найду современный компилятор, который не заставил бы оба выражения оценивать одинаковое значение, даже если наборы символов исполнения и исходного кода грубо несовместимы. Современные компиляторы, как правило, имеют интегрированные препроцессоры - этапы с 1 по 7 выполняются одной и той же программой, и даже если они этого не делают, инженерное бремя специализации препроцессора в соответствии с его исполнением, установленным для самого компилятора, тривиально в настоящее время.