Почему 0f не рассматривается как литерал с плавающей запятой в C++?

Почему 0f не рассматривается как литерал с плавающей запятой в C++?

#include <iostream>

using namespace std;

int main(){
  cout << 0f << endl;

  return 0;
}

Компиляция вышеизложенного дает мне

C2509 (синтаксическая ошибка: «неверный суффикс в номере»)

с помощью VS2008.


person Agnel Kurian    schedule 18.10.2010    source источник
comment
Почему на вопросы о небольших произвольных точках в языковом дизайне обычно нельзя ответить удовлетворительно.   -  person David Thornley    schedule 18.10.2010
comment
@ Дэвид - Спасибо, чувак. Это очень информативно.   -  person Agnel Kurian    schedule 18.10.2010
comment
@Vulcan: К сожалению, это настолько информативно, насколько это возможно. Вы не становитесь лучше, чем ответы Оли Чарльзворта и Дакоты Хокинс ниже, и вы недовольны ими. По сути, вы спрашиваете о причинах небольшого решения в грамматике C, которое было принято более тридцати лет назад. Вполне вероятно, что явной причины не было.   -  person David Thornley    schedule 18.10.2010
comment
Трудно понять, почему у этого вопроса 6 голосов против. Это хороший вопрос, который дает представление о работе парсера и сканера.   -  person codaddict    schedule 19.10.2010
comment
@coaddict: я не думаю, что за него нужно проголосовать, но в то же время я не думаю, что мы узнали что-то интересное о парсере! Это просто произвольная спецификация языка, которая на практике не имеет никакого значения.   -  person Oliver Charlesworth    schedule 20.10.2010
comment
@ Оли, я бы не был так абсолютно уверен, что на практике это не имеет никакого значения.   -  person Agnel Kurian    schedule 20.10.2010
comment
@Vulcan: Можешь привести контрпример?   -  person Oliver Charlesworth    schedule 20.10.2010


Ответы (6)


Если бы для этого дизайнерского решения была явно указана причина, она была бы в документе «Обоснование» C99 (C++ скопировал все это дословно из C без повторного рассмотрения). Но нет. Это все, что сказано о суффиксе «f»:

§6.4.4.2 Плавающие константы

В соответствии с существующей практикой константа с плавающей запятой имеет тип double. Поскольку C89 позволяет выражениям, содержащим только операнды float, выполняться с помощью float арифметики, а не double, метод явного выражения float< /strong> желательно константы. Аналогичные проблемы возникают и с типом long double.

Суффиксы F и L были добавлены для передачи информации о типе с плавающими константами, подобно суффиксу L для длинных целых чисел. Тип плавающих констант по умолчанию остается двойным для совместимости с предыдущей практикой. В качестве суффиксов также разрешены строчные буквы f и l.

Однако есть подразумеваемая причина. Обратите внимание на формулировку: «суффиксы ... были добавлены для передачи информации о типе с плавающими константами». Авторы стандарта считали, что числовые константы уже однозначно являются либо целым числом, либо с плавающей запятой к тому времени, когда вы доберетесь до суффикса. Суффикс предназначен только для дополнительной специфики внутри категории, он не может переводить число из одной категории в другую. Это подтверждается фактической грамматикой (C99 §6.4.4), которая сначала определяет числовые константы либо как целочисленные константы, либо как константы с плавающей запятой, а затем определяет отдельные классы. суффиксов для каждого.

person zwol    schedule 29.10.2010
comment
+1. Это единственный ответ, который действительно дает представление о вероятном обосновании этого решения. - person Brian; 29.10.2010

Предполагая, что грамматика, используемая C++ для констант с плавающей запятой, такая же, как и для 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 из 0f будет использоваться лексическим анализатором как целочисленная константа D, а f будет использоваться как токен FS. Теперь, когда синтаксический анализ видит D, за которым следует FS, для которого нет правила сопоставления, он выдает ошибку:

error: invalid suffix "f" on integer constant
person codaddict    schedule 19.10.2010

Потому что 0 - это целочисленная константа.

редактировать: сообщение об ошибке, данное codepad.org (предположим, g++), может быть немного проще для понимания. "ошибка: неверный суффикс "f" в целочисленной константе". «0.f» будет работать, потому что 0. (или 0.0, то же самое) является десятичной константой, и запрос на то, чтобы десятичная константа была с плавающей запятой, имеет больше смысла, чем запрос на то, чтобы целочисленная константа была с плавающей запятой :)

person Dakota Hawkins    schedule 18.10.2010
comment
@Dakota, именно поэтому я добавил суффикс «f», чтобы заставить компилятор рассматривать его как число с плавающей запятой. - person Agnel Kurian; 18.10.2010
comment
f может применяться только к двойному литералу (например, 0.0), а 0 является литералом int. - person Etienne de Martel; 18.10.2010
comment
@ Этьен, и вопрос в том, почему? - person Agnel Kurian; 18.10.2010
comment
А, потому что так написано в стандарте? Я знаю, что это дерьмовый ответ, но я не могу придумать другой причины. - person Etienne de Martel; 18.10.2010
comment
Тогда я полагаю, ваш ответ, потому что так оно и работает. Компилятор обрабатывает целочисленные константы и десятичные константы по-разному. 0.0 сам по себе будет двойным, поэтому вы можете добавить «f», чтобы сделать его плавающим. 0 сам по себе будет целым числом, и суффиксы с плавающей запятой не будут применяться. Точно так же 0.0UL, вероятно, не будет компилироваться. - person Dakota Hawkins; 18.10.2010
comment
@Vulcan Eager: Это действительно важно, почему? это так же важно, как вопрос, почему для индексации массива вы используете [], а не ‹›, или почему точкой входа для вашей программы является функция с именем main, а не StartHere. Нет причин, кроме 'потому что так сказано в стандарте - person David Rodríguez - dribeas; 18.10.2010

Потому что вам нужно 0.0f.

person Oliver Charlesworth    schedule 18.10.2010
comment
Я знаю, что 0.0f заставляет компилятор замолчать. Но это все еще не объясняет, почему суффикс «f» сам по себе не поможет. - person Agnel Kurian; 18.10.2010
comment
@Vulcan: Наверное, просто так. По сути, я повторяю мнение Дэвида Торнели выше. - person Oliver Charlesworth; 18.10.2010

Вот вам «потому что»: если константа int с суффиксом f автоматически преобразуется в float, то 0x0f будет неоднозначной.

person TonyK    schedule 14.05.2012
comment
Не обязательно; суффикс 0x при отсутствии суффикса p+EXP или p-EXP уже рассматривается как принуждение к целочисленности (т. е. 0x0.0 является синтаксической ошибкой); с 0x0.0p+0f нет двусмысленности, потому что показатель степени десятичный, хотя мантисса шестнадцатеричная. Тем не менее, это все еще отличный момент, который вполне мог быть в умах членов комитета. - person zwol; 12.09.2012

Это не обязательно единственная причина, но суффикс l или L может применяться к целочисленному литералу или к литералу с плавающей запятой. 42L относится к типу long int; 42.0L относится к типу long double.

Числовой литерал с суффиксом L должен быть устранен неоднозначностью, чтобы определить, является ли он целым числом или числом с плавающей запятой. Разрешение суффиксу F определять тип литерала само по себе было бы непоследовательным и потенциально запутанным. Это также затруднит добавление новых суффиксов в будущих версиях языка.

person Keith Thompson    schedule 09.06.2015