Почему "0f" не рассматривается как литерал с плавающей запятой в С++?
Почему не 0f
рассматривается как литерал с плавающей запятой в С++?
#include <iostream>
using namespace std;
int main(){
cout << 0f << endl;
return 0;
}
Компиляция приведенного выше дает мне
C2509 (синтаксическая ошибка: "плохой суффикс на номер" )
используя VS2008.
Ответы
Ответ 1
Если была явная заявленная причина для этого проектного решения, это было бы в документе C99 "Обоснование" (С++ скопировал все это дословно из C, не переосмыслив его). Но нет. Это все, что говорится о суффиксе "f":
§6.4.4.2 Плавающие константы
В соответствии с существующей практикой константа с плавающей запятой определяется как имеющая введите double
. Поскольку C89 допускает выражения, содержащие только операнды float
для выполнения в float
арифметике, а не double
, метод желательно выражать явные константы float
. Тип long double
вызывает аналогичные проблемы.
Добавлены суффиксы F
и L
для передачи информации типа с помощью плавающие константы, как и суффикс L
, для длинных целых чисел. По умолчанию тип плавающих констант остается двойным для совместимости с предшествующей практикой. В качестве суффиксов также допускаются нижний регистр F
и L
.
Однако есть определенная причина. Обратите внимание на формулировку: "добавлены суффиксы для передачи информации типа с плавающими константами". Авторы стандарта думали о числовых константах, поскольку уже были однозначно либо целыми, либо с плавающей точкой к моменту поступления в суффикс. Суффикс предназначен только для дополнительной специфичности внутри категории, он не может переворачивать число из одной категории в другую. Это подкрепляется фактической грамматикой (C99 §6.4.4), которая сначала определяет числовые константы как целые константы или плавающие константы, а затем определяет отдельные классы суффиксов для каждого.
Ответ 2
Предполагая, что грамматика, используемая С++ для констант с плавающей запятой, такая же, как для C (что, я думаю, верно), мы имеем:
Определения некоторых ярлыков, взятых из ANSI C grammar
D [0-9]
L [a-zA-Z_]
H [a-fA-F0-9]
E [Ee][+-]?{D}+
FS (f|F|l|L)
IS (u|U|l|L)*
Теперь f
или f
, которые вы видите в конце плавающих точек, определены в FS
выше.
Теперь давайте рассмотрим грамматику для распознавания действительных констант с плавающей запятой:
{D}+{E}{FS}?
{D}*"."{D}+({E})?{FS}?
{D}+"."{D}*({E})?{FS}?
Теперь, если вы видите внимательно, нет правила, которое бы идентифицировало 0f
.
Используя правило 1, мы можем иметь 0e0f
Используя правило 2, мы можем иметь .0f
или 0.0f
Используя правило 3, мы можем иметь 0.f
или 0.0f
Что на самом деле происходит в вашем случае: 0
of 0f
будет потребляться лексическим анализатором как целочисленная константа D
, а f
будет использоваться как токен FS
. Теперь, когда синтаксический анализ видит a D
, за которым следует FS
, для которого нет соответствующего правила, оно выплевывает ошибку:
error: invalid suffix "f" on integer constant
Ответ 3
Потому что 0 - целочисленная константа.
edit: сообщение об ошибке, данное codepad.org(предположим g++), может быть немного легче понять. msgstr "ошибка: недопустимый суффикс" f "для целочисленной константы". "0.f" будет работать, потому что 0. (или 0.0, то же самое) является десятичной константой, и просить десятичную константу быть float имеет больше смысла, чем просить целочисленную константу быть float:)
Ответ 4
Потому что вам нужно 0.0f
.
Ответ 5
Здесь "потому что" для вас: если константа int
с суффиксом f
была автоматически преобразована в float
, тогда 0x0f
будет неоднозначным.
Ответ 6
Это не обязательно единственная причина, но суффикс l
или l
может быть применен к целочисленному литералу или к литералу с плавающей запятой. 42L
имеет тип long int
; 42.0L
имеет тип long double
.
Числовой литерал с суффиксом l
должен быть неоднозначным, чтобы определить, является ли оно целым или плавающим. Разрешить суффикс F
сам по себе, чтобы определить тип литерала, будет непоследовательным и потенциально запутанным. Это также затруднит добавление новых суффиксов в будущих версиях языка.