int main ()
{
int a = 5,b = 2;
printf("%d",a+++++b);
return 0;
}
Этот код дает следующую ошибку:
ошибка: lvalue требуется как операнд приращения
Но если я поставлю пробелы a++ +
и ++b
, тогда все будет нормально.
int main ()
{
int a = 5,b = 2;
printf("%d",a++ + ++b);
return 0;
}
Что означает ошибка в первом примере?
x+++++y
анализируется какx ++ ++ + y
, что нарушает ограничение на операторы приращения, даже если синтаксический анализx ++ + ++ y
может дать правильное выражение».Ответы:
printf("%d",a+++++b);
интерпретируется как в(a++)++ + b
соответствии с максимальным правилом Мунка ! .++
(постфикс) не вычисляет значение,lvalue
но требует, чтобы его операнд былlvalue
.! 6.4 / 4 говорит, что следующий токен предварительной обработки - это самая длинная последовательность символов, которая может составлять токен предварительной обработки "
источник
Компиляторы пишутся поэтапно. Первый этап называется лексером и превращает символы в символическую структуру. Таким образом, "++" становится чем-то вроде
enum SYMBOL_PLUSPLUS
. Позже этап синтаксического анализатора превращает это в абстрактное синтаксическое дерево, но не может изменить символы. Вы можете повлиять на лексический анализатор, вставив пробелы (завершающие символы, если они не заключены в кавычки).Обычные лексеры жадные (за некоторыми исключениями), поэтому ваш код интерпретируется как
На вход парсера поступает поток символов, поэтому ваш код будет выглядеть примерно так:
[ SYMBOL_NAME(name = "a"), SYMBOL_PLUS_PLUS, SYMBOL_PLUS_PLUS, SYMBOL_PLUS, SYMBOL_NAME(name = "b") ]
Что синтаксический анализатор считает синтаксически неверным. (РЕДАКТИРОВАТЬ на основе комментариев: семантически неверно, потому что вы не можете применить ++ к r-значению, что приводит к ++)
является
Что нормально. Как и другие ваши примеры.
источник
a++
).a++
приводит к rvalue.x = 10&987&&654&&321
это незаконно, но, как ни странно,x = 10&987&&654&&&321
законно.Лексер использует так называемый алгоритм «максимального пережевывания» для создания токенов. Это означает, что пока он читает символы, он продолжает читать символы, пока не встретит что-то, что не может быть частью того же токена, что у него уже есть (например, если он читал цифры, поэтому то, что у него есть, является числом, если он встречает an
A
, он знает, что не может быть частью числа. поэтому он останавливается и оставляетA
во входном буфере для использования в качестве начала следующего токена). Затем он возвращает этот токен синтаксическому анализатору.В данном случае это означает, что оно
+++++
будет преобразовано вa ++ ++ + b
. Поскольку первый постинкремент дает r-значение, второе не может быть применено к нему, и компилятор выдает ошибку.Просто FWIW, в C ++ вы можете перегрузить,
operator++
чтобы получить lvalue, что позволяет этому работать. Например:struct bad_code { bad_code &operator++(int) { return *this; } int operator+(bad_code const &other) { return 1; } }; int main() { bad_code a, b; int c = a+++++b; return 0; }
Компилируется и запускается (хотя ничего не делает) с помощью имеющихся у меня компиляторов C ++ (VC ++, g ++, Comeau).
источник
16FA
- это прекрасное шестнадцатеричное число , содержащее A.0x
в начале он все равно будет обрабатывать это так, как16
следуетFA
, а не одно шестнадцатеричное число.0x
не входили в число.x
цифры, это казалось совершенно ненужным.Этот точный пример описан в проекте стандарта C99 (те же подробности в C11 ), раздел 6.4 Лексические элементы, параграф 4, в котором говорится:
которое также известно как правило максимального пережевывания, которое используется в лексическом анализе, чтобы избежать двусмысленности, и работает, беря как можно больше элементов, чтобы сформировать действительный токен.
в абзаце также есть два примера, второй точно соответствует вашему вопросу и выглядит следующим образом:
что говорит нам, что:
будет проанализирован как:
что нарушает ограничения на приращение поста, так как результатом первого приращения поста является rvalue, а приращение поста требует lvalue. Это описано в разделе «
6.5.2.4
Операторы увеличения и уменьшения Postfix», в котором говорится ( выделено мной ):а также
Книга C ++ Gotchas также рассматривает этот случай в
Gotcha #17
Максимальных задачах Мунка, это та же проблема в C ++, а также дает несколько примеров. Это объясняет, что при работе со следующим набором символов:лексический анализатор может делать одно из трех:
-
,>
и*
->
и*
->*
Максимальное жуют правило позволяет избежать этих неясностей. Автор указывает, что это ( в контексте C ++ ):
Первым примером могут быть шаблоны, аргументы которых также являются шаблонами ( что было решено в C ++ 11 ), например:
list<vector<string>> lovos; // error! ^^
Что интерпретирует закрывающие угловые скобки как оператор сдвига , и поэтому для устранения неоднозначности требуется пробел:
list< vector<string> > lovos; ^
Во втором случае используются аргументы по умолчанию для указателей, например:
void process( const char *= 0 ); // error! ^^
будет интерпретироваться как
*=
оператор присваивания, решение в этом случае - указать параметры в объявлении.источник
>>
Правило задается по адресу: stackoverflow.com/questions/15785496/…Ваш компилятор отчаянно пытается разобрать
a+++++b
и интерпретирует его как(a++)++ +b
. Теперь результат post-increment (a++
) не является lvalue , т. Е. Он не может быть увеличен снова.Пожалуйста, никогда не пишите такой код в программах производственного качества. Подумайте о бедняге, идущем за вами, которому нужно интерпретировать ваш код.
источник
a ++ возвращает предыдущее значение, rvalue. Вы не можете увеличить это значение.
источник
Потому что это вызывает неопределенное поведение.Который из них?
Да, ни вы, ни компилятор этого не знаете.РЕДАКТИРОВАТЬ:
Настоящая причина в том, что говорят другие:
Это интерпретируется как
(a++)++ + b
.но приращение поста требует lvalue (которое является переменной с именем), но (a ++) возвращает rvalue, которое не может быть увеличено, что приводит к появлению сообщения об ошибке.
Спасибо остальным, что указали на это.
источник
a+++b
что всегдаa++ + b
a++ ++ +b
что не может быть проанализировано.a+++++b
дает оценку(a++)++)+b
. Конечно, с GCC, если вы вставите эти скобки и перестроите, сообщение об ошибке не изменится.Я думаю, что компилятор видит это как
c = ((a ++) ++) + b
++
должен иметь в качестве операнда значение, которое можно изменить. a - это значение, которое можно изменить.a++
однако это "rvalue", его нельзя изменить.Кстати ошибка я вижу на GCC C это то же самое, но по- другому сформулированное:
lvalue required as increment operand
.источник
Следуйте этому порядку прецедента
1. ++ (предварительное приращение)
2. + - (сложение или вычитание)
3. «x» + «y» складывают обе последовательности
int a = 5,b = 2; printf("%d",a++ + ++b); //a is 5 since it is post increment b is 3 pre increment return 0; //it is 5+3=8
источник