Что такое оператор «->» в C ++?

После прочтения скрытых объектов и темные углы C ++ / STL на comp.lang.c++.moderated, я был полностью удивлен , что следующий фрагмент кода компилируется и работает как в Visual Studio 2008 и G ++ 4.4.

Вот код:

#include <stdio.h>
int main()
{
    int x = 10;
    while (x --> 0) // x goes to 0
    {
        printf("%d ", x);
    }
}

Вывод:

9 8 7 6 5 4 3 2 1 0

Я бы предположил, что это C, так как он работает и в GCC. Где это определено в стандарте и откуда оно взято?

29.10.2009 06:57:45
Или даже просто правильный интервал ... Я не думаю, что когда-либо видел пробел между переменной и тем ++или --
Matthew Scharley 29.10.2009 07:09:47
Этот оператор «идет» может быть отменен (0 <- x). А также есть оператор «бежит к» (0 <---- x). Боже, самая забавная вещь, которую я когда-либо слышал о синтаксисе c ++ =) +1 за вопрос.
SadSido 29.10.2009 07:27:21
Как ни странно, хотя интерпретация очень неправильная, она описывает, что код делает правильно. :)
Noldorin 11.11.2009 13:51:39
Представьте себе новые возможности синтаксиса: #define upto ++<, #define downto -->. Если вы чувствуете зло, вы можете сделать #define for while(и #define do ) {#define done ;}) и написать for x downto 0 do printf("%d\n", x) doneо, человечество ...
Chris Lutz 4.03.2010 07:07:25
Открывает возможность совершенно нового выразительного способа кодирования, который стоит пожертвовать несколькими предупреждениями компилятора: bool CheckNegative (int x) {return x <0? верно :-( неверно); }
ttt 28.05.2012 11:12:58
23 ОТВЕТА
РЕШЕНИЕ

-->не оператор. Это на самом деле два отдельных оператора, --и >.

Код условия уменьшает значение x, возвращая xисходное (не уменьшенное) значение, а затем сравнивает исходное значение с 0использованием >оператора.

Чтобы лучше понять, заявление можно записать следующим образом:

while( (x--) > 0 )
8516
23.12.2018 15:46:05
С другой стороны, в этом контексте это выглядит как некий оператор диапазона.
Charles Salvia 29.10.2009 07:14:52
Сказать, что x пост-уменьшен, а затем сравнивается с 0 - то же самое, что сказать, что x уменьшается после сравнения с 0
Charles Salvia 29.10.2009 08:35:27
Я не думаю, что это то же самое. Я думаю, что слово «затем» подразумевает, что есть порядок (после пост-убывания значение х становится на единицу меньше). Я думаю, что можно сказать «Вы отправляете убывание x, а затем сравниваете его старое значение и 0 ...», чтобы сделать его более понятным. Но это все равно придирки. Мы все знаем, что имеется в виду.
Johannes Schaub - litb 30.01.2010 17:42:40
На Java это также компилируется :)
Steven Devijver 12.02.2013 08:07:27
Имя @Jay - плохой стиль программирования :-) Об этом свидетельствует тот факт, что вопрос был задан в первую очередь. Гораздо больше смысла в текстовом связывании операторов с тем, над чем они работают, а не с чем-то не связанным, так while (x-- > 0)что было бы более подходящим. Это также делает более очевидным, что происходит (по крайней мере, в редакторе с фиксированным шрифтом), означая, что скобки в этом ответе не будут необходимы.
paxdiablo 15.02.2016 01:28:00

Это эквивалентно

while (x-- > 0)

x--(после декремента) эквивалентно x = x-1так, код преобразуется в:

while(x > 0) {
    x = x-1;
    // logic
}
x--;   // The post decrement done when x <= 0
1268
25.04.2020 10:16:27
Это не совсем верно. Значение x внутри тела цикла отличается во втором случае. Оператор присваивания в вашем примере должен быть выше логики, чтобы он был эквивалентным. Postfix - вычитает 1, но сравнение будет происходить со значением до вычитания.
uliwitness 16.10.2018 16:03:48
@uliwitness Они действительно эквивалентны. Было бы неправильно, если бы использовался префикс: 0 >-- xв этом случае xуменьшается перед логикой. В постфиксе логика выполняется перед уменьшением, и, таким образом, оба образца эквивалентны. Не стесняйтесь записывать их в Consoleи тестировать их.
Emma 2.01.2019 19:36:20
Они все еще не эквивалентны. После первого цикла x равен -1 (или переполняется в случае, если он не подписан), после второго он равен 0. (Если исходить из того, что x начинается неотрицательно, ни один цикл не изменяет x, не прерывает или ...)
Caesar 15.01.2019 14:56:57
while(x=x-1,x+1 > 0)эквивалентно.
S.S. Anne 16.03.2020 19:25:41
@Shebham, вот контрольный пример: если x начинается с 0, в исходном цикле он будет выходить как -1, а с вашей версией он останется равным нулю. Так что они не эквивалентны.
Elliott 20.03.2020 13:46:00

Это

#include <stdio.h>
int main(void){
     int x = 10;

     while( x-- > 0 ){ // x goes to 0

       printf("%d ", x);
     }

     return 0;
}

Просто пространство заставляет вещи выглядеть смешно, --уменьшать и >сравнивать.

545
8.03.2018 17:02:25
while( x-- > 0 )

Вот как это проанализировано.

363
19.11.2009 19:46:56

Это очень сложный оператор, поэтому даже ISO / IEC JTC1 (Объединенный технический комитет 1) поместил свое описание в две разные части стандарта C ++.

Шутки в сторону, они представляют собой два разных оператора: --и >описаны , соответственно , в §5.2.6 / 2 и §5.9 на C ++ 03 стандарта.

2372
2.10.2019 08:08:39

В любом случае, у нас теперь есть оператор «идет». "-->"его легко запомнить как направление, а «пока х уходит в ноль» означает прямое значение.

Кроме того, это немного более эффективно, чем "for (x = 10; x > 0; x --)"на некоторых платформах.

239
28.02.2013 17:28:13
Идет не может быть правдой всегда, особенно когда значение х является отрицательным.
Ganesh Gopalasubramanian 13.11.2009 03:22:41
Другая версия не делает то же самое - for (size_t x=10; x-->0; )тело цикла выполняется с 9,8, .., 0, тогда как другая версия имеет 10,9, .., 1. В противном случае выйти из цикла с нуля с помощью переменной без знака довольно сложно.
Pete Kirkham 21.06.2010 08:57:44
Я думаю, что это немного вводит в заблуждение ... У нас нет буквального оператора "идет к", так как нам нужен еще один, ++>чтобы сделать дополнительную работу.
tslmy 15.06.2013 02:49:10
@Josh: на самом деле, переполнение дает неопределенное поведение для int, так что он может так же легко съесть вашу собаку, как xи обнулить, если она начинается отрицательно.
SamB 6.12.2013 06:57:56
Это очень важная для меня идиома по причине, указанной в comnmet @PeteKirkham, так как мне часто приходится делать убывающие циклы над беззнаковыми величинами вплоть до 0. (Для сравнения, идиома пропуска тестов на ноль, таких как запись while (n--)вместо «без знака» n, ничего не покупает, и для меня сильно затрудняет читаемость.) Он также обладает приятным свойством указывать на один больше, чем начальный индекс, который обычно Вы хотите (например, для цикла над массивом вы указываете его размер). Мне также нравится -->без места, так как это позволяет легко распознать идиому.
Marc van Leeuwen 30.08.2014 20:08:39

Использование -->имеет историческую значимость. Уменьшение было (и остается в некоторых случаях) быстрее, чем увеличение в архитектуре x86. Использование -->предполагает, что xсобирается 0, и обращается к тем, кто имеет математическое образование.

428
18.11.2009 12:47:41
Не совсем верно. Уменьшение и увеличение занимают одинаковое количество времени, преимущество в том, что сравнение с нулем происходит очень быстро по сравнению со сравнением с переменной. Это верно для многих архитектур, а не только для x86. Что-нибудь с инструкцией JZ (прыгать, если ноль). В поисках вы можете найти множество циклов for, которые записаны в обратном направлении, чтобы сохранить циклы при сравнении. Это особенно быстро на x86, так как действие по уменьшению переменной устанавливает соответствующий флаг нуля, так что вы можете затем перейти без необходимости явно сравнивать переменную.
burito 30.12.2009 05:16:46
Ну, уменьшение до нуля означает, что вам нужно сравнивать только с 0 на каждую итерацию цикла, в то время как итерация к n означает сравнение с n на каждой итерации. Первый способ проще (и на некоторых архитектурах он автоматически тестируется после каждой операции с регистром данных).
Joey Adams 12.04.2010 15:07:58
@burrito Хотя я не согласен, циклы, обусловленные ненулевыми значениями, обычно предсказываются почти идеально.
Duncan 11.01.2014 09:05:12
Инкремент и декремент одинаково быстр, вероятно, на всех платформах (определенно на x86). Разница заключается в тестировании условия окончания цикла. Чтобы увидеть, достиг ли счетчик нуля, он практически свободен - когда вы уменьшаете значение, в процессоре устанавливается нулевой флаг, и для определения конечного условия вам просто нужно проверить этот флаг, тогда как при увеличении необходимо выполнить операцию сравнения перед конечным условием может быть обнаружен.
lego 18.02.2015 11:14:01
Конечно, все это спорно в эти дни, так как современные компиляторы могут векторизации и обратные петли автоматически.
Lambda Fairy 20.02.2015 03:53:56

Этот код сначала сравнивает x и 0, а затем уменьшает x. (Также сказано в первом ответе: вы после x уменьшаете, а затем сравниваете x и 0 с >оператором.) Смотрите вывод этого кода:

9 8 7 6 5 4 3 2 1 0

Теперь мы сначала сравним, а затем уменьшим, увидев 0 в выводе.

Если мы хотим сначала уменьшить, а затем сравнить, используйте этот код:

#include <stdio.h>
int main(void)
{
    int x = 10;

    while( --x> 0 ) // x goes to 0
    {
        printf("%d ", x);
    }
    return 0;
}

Этот вывод:

9 8 7 6 5 4 3 2 1
219
3.01.2016 17:48:14

Между --и >. Отсутствует пробел . xявляется пост уменьшенным, то есть уменьшенным после проверки условия x>0 ?.

146
22.11.2010 19:02:21
Пробел не пропущен - C (++) игнорирует пробел.
user529758 2.08.2012 19:16:31
@ H2CO3 Это не совсем так. Есть места, где пробел должен использоваться для разделения токенов, например, в #define foo()сравнении с #define foo ().
Jens 25.04.2013 21:16:44
@Jens Как насчет: «Пробел не пропущен - C (++) игнорирует ненужные пробелы.»?
Kevin P. Rice 4.12.2013 20:35:14

Это точно так же, как

while (x--)
{
   printf("%d ", x);
}

для неотрицательных чисел

272
30.04.2015 22:48:34
Не должно ли это быть for(--x++;--x;++x--)?
Mateen Ulhaq 4.12.2011 21:32:19
@DoctorT это то, что unsignedдля
Cole Johnson 23.03.2013 18:39:13
@MateenUlhaq, это неправильно в соответствии со стандартом, выражение --x++имеет неопределенное поведение в соответствии с §1.9.15
WorldSEnder 19.06.2015 02:02:01
Если бы он использовал unsigned, он бы использовал%u
Cacahuete Frito 21.02.2019 22:01:27

Мой компилятор распечатает 9876543210 при запуске этого кода.

#include <iostream>
int main()
{
    int x = 10;

    while( x --> 0 ) // x goes to 0
    {
        std::cout << x;
    }
}

Как и ожидалось. На while( x-- > 0 )самом деле означает while( x > 0). x--Пост декрементирует x.

while( x > 0 ) 
{
    x--;
    std::cout << x;
}

это другой способ написать то же самое.

Приятно, что оригинал выглядит как «пока х уходит в 0».

175
30.04.2015 22:49:12
Результат не определен, только если вы увеличиваете / уменьшаете одну и ту же переменную более одного раза в одном выражении. Это не относится к этой ситуации.
Tim Leaf 5.05.2010 15:30:19
while( x-- > 0 ) actually means while( x > 0)- Я не уверен, что вы пытались сказать там, но то, как вы это сформулировали, подразумевает, что --это не имеет никакого значения, что, очевидно, очень неправильно.
Dukeling 22.05.2015 12:28:30
Для того, чтобы управлять точки дома из @Dukeling, этот ответ не то же самое , что и оригинальный пост. В оригинальном посте xбудет -1после того, как он выйдет из цикла, а в этом ответе xбудет 0.
Mark Lakata 24.02.2020 16:41:38

--является оператором декремента и >является оператором больше, чем .

Два оператора применяются как один, как -->.

138
29.10.2011 21:42:06
Они применяются как 2 отдельных оператора. Они только написаны обманчиво выглядеть как «один один».
underscore_d 12.11.2016 17:56:09

В одной книге, которую я прочитал (я не помню, какая именно книга), говорилось: компиляторы пытаются анализировать выражения по самому большому токену , используя правило левого и правого.

В этом случае выражение:

x-->0

Разборы по самым большим токенам:

token 1: x
token 2: --
token 3: >
token 4: 0
conclude: x-- > 0

То же правило применяется к этому выражению:

a-----b

После разбора:

token 1: a
token 2: --
token 3: --
token 4: -
token 5: b
conclude: (a--)-- - b

Я надеюсь, что это помогает понять сложное выражение ^^

319
23.04.2015 09:02:58
Ваше второе объяснение не правильно. Компилятор увидит a-----bи подумает (a--)-- - b, что не компилируется, потому a--что не возвращает lvalue.
Tim Leaf 5.05.2010 15:26:03
Дополнительно xи --есть два отдельных токена.
Roland Illig 2.07.2010 19:20:05
@DoctorT: он проходит лексер. только семантический проход способен испустить эту ошибку. поэтому его объяснение верно.
v.oddou 1.09.2014 03:34:53
Пока вы думаете, что -->это оператор (что подразумевается под вопросом, который был задан), этот ответ вообще не поможет - вы будете думать, что маркер 2 - это -->не просто так --. Если вы знаете, что -->это не оператор, у вас, вероятно, нет проблем с пониманием кода в вопросе, поэтому, если у вас нет совершенно другого вопроса, я не совсем уверен, как это может быть полезно.
Dukeling 22.05.2015 12:33:43
Пример @DoctorT может быть правильным, если предположить, что aперегружен оператор пост-декремента, который возвращает lvalue. coliru.stacked-crooked.com/a/e1effc351ae79e9f
doc 8.07.2015 11:20:12

Совершенно отвратительный, но я буду использовать это:

#define as ;while

int main(int argc, char* argv[])
{
    int n = atoi(argv[1]);
    do printf("n is %d\n", n) as ( n --> 0);
    return 0;
}
356
3.12.2011 02:33:05
@SAFX - Это были бы совершенно иероглифы с египетскими скобками
mouviciel 14.11.2012 10:00:02
Это не компилируется. C не Паскаль, где внутренняя часть do ... whileявляется списком операторов. В С это блок, так и должно быть do { ... } while.
user207421 11.09.2016 02:20:23
@EJP это компилируется. Синтаксис есть do statement while ( expression ) ;. Сказав это, я надеюсь, что это поняли, я имел в виду пример как шутку.
Escualo 18.10.2016 17:28:10

Или для чего-то совершенно другого ... xслайды 0.

while (x --\
            \
             \
              \
               > 0)
     printf("%d ", x);

Не так математично, но ... каждая картина рисует тысячу слов ...

3091
8.01.2020 22:51:59
@mafutrct - насколько я помню \ в C просто добавляет следующую строку, как будто не было перевода строки. Здесь в основном ничего не делают.
Hogan 10.03.2012 04:37:36
@mafu символ '\' сообщает компилятору, что текущая строка продолжается в следующей строке, поэтому компилятор должен объединить обе строки и скомпилировать их как одну. 'while (x -> 0)' будет работать до тех пор, пока x не станет равным -1. Но то, как он делает отступы, делает вид, будто х скользит к нулю. «Пока х сползает к 0 ...»
Felype 20.05.2013 18:10:06
IIRC, K & R C допускали пробел между '-s в операторе декремента, в этом случае вы могли бы иметь обратную косую черту в середине, что выглядело бы еще круче. :)
Jules 13.07.2013 09:23:17
@ArnavBorborah - это старое значение выражения why waste words when a picture does a better job, используемое в этом контексте как шутка. (есть на самом деле 2 ключевых слова whileи printf)
unsynchronized 10.09.2016 11:36:46
Ах да, неясный оператор слайдов. Как я мог забыть!
demonkoryu 27.10.2017 10:00:48

На самом деле, xпост-декремент и с этим условием проверяется. Это не -->так(x--) > 0

Примечание: значение xизменяется после проверки условия, потому что оно после уменьшения. Также могут возникнуть некоторые подобные случаи, например:

-->    x-->0
++>    x++>0
-->=   x-->=0
++>=   x++>=0
122
12.04.2014 09:52:33
За исключением того, что ++> вряд ли можно использовать в какое-то время (). Оператор "идет до ..." будет ++ <, что выглядит не очень хорошо. Оператор -> это счастливое совпадение.
Florian F 1.09.2014 09:46:25
@BenLeggiero Это может «сработать» в смысле генерации кода, который что-то делает (в то же время приводя в бешенство читателей, которые не любят фальшиво-умный код), но семантика отличается, так как использование предопределенного кода означает, что он будет выполнять на одну итерацию меньше. В качестве надуманного примера, он никогда не будет выполнять тело цикла, если xначнется с 1, но while ( (x--) > 0 )будет. {edit} Эрик Липперт освещал оба в своих заметках о выпуске C # 4: blogs.msdn.microsoft.com/ericlippert/2010/04/01/…
underscore_d 12.11.2016 17:57:29

Это комбинация двух операторов. Первый --- для уменьшения значения и >для проверки, больше ли значение, чем правый операнд.

#include<stdio.h>

int main()
{
    int x = 10;

    while (x-- > 0)
        printf("%d ",x);

    return 0;
}

Выход будет:

9 8 7 6 5 4 3 2 1 0            
128
30.04.2015 22:50:01

C и C ++ подчиняются правилу "максимальное жевание". Точно так же, как a --- b переводится (a--) - b, в вашем случае x-->0переводится как (x--)>0.

По сути, это правило говорит о том, что при движении слева направо выражения формируются путем взятия максимального количества символов, которые образуют правильное выражение.

119
12.04.2014 09:55:16
Именно это и предполагал ФП: «((a) ->)» был максимальным глотком. Оказывается, исходное предположение ОП было неверным: «->» не является максимально допустимым оператором.
david 28.08.2014 00:41:45
Также известен как жадный разбор, если я правильно помню.
Roy Tinker 11.07.2015 01:04:15
@RoyTinker Жадное сканирование. Парсер не имеет к этому никакого отношения.
user207421 11.09.2016 02:21:50

x может идти к нулю еще быстрее в обратном направлении:

int x = 10;

while( 0 <---- x )
{
   printf("%d ", x);
}

8 6 4 2

Вы можете контролировать скорость стрелкой!

int x = 100;

while( 0 <-------------------- x )
{
   printf("%d ", x);
}

90 80 70 60 50 40 30 20 10

;)

1187
11.10.2017 02:51:48
какая операционная система, этот тип вывода генерируется, я использую Ubuntu 12.04 в том, что у меня было сообщение об ошибке
Bhuvanesh 19.01.2015 12:13:36
Хотя это должно быть очевидно, для всех новичков в C ++ читающих это: не делайте этого. Просто используйте расширенное назначение, если вам нужно увеличить / уменьшить более чем на единицу.
Blimeo 26.03.2015 02:41:40
Ноль с "лазерами". в то время как (0> - - - - - - - - - - - x) ... тот же вывод.
Samuel Danielson 9.03.2016 21:54:16
@phord ты уверен, что он не компилируется? -> coliru.stacked-crooked.com/a/5aa89a65e3a86c98
doc 24.03.2016 10:43:16
@doc. Компилируется в c ++, но не в c.
phord 25.03.2016 14:58:46

Почему все осложнения?

Простой ответ на оригинальный вопрос просто:

#include <stdio.h>
int main()
{
    int x = 10;
    while (x > 0) 
    {
        printf("%d ", x);
        x = x-1;
    }
}

Делает то же самое. Я не говорю, что вы должны делать это так, но он делает то же самое и ответил бы на вопрос в одном посте.

Это x--просто сокращение для вышеупомянутого, и >это просто обычное значение больше, чем operator. Нет большой загадки!

Сейчас слишком много людей делают простые вещи сложными;)

27
30.06.2018 10:10:56
Этот вопрос не о сложностях, а о ** скрытых особенностях и темных углах C ++ / STL **
pix 27.10.2016 15:32:01
Программа здесь дает другой вывод, чем оригинальный, потому что здесь x уменьшается после printf. Это хорошо демонстрирует, как «простые ответы» обычно неверны.
Öö Tiib 13.05.2017 09:30:30
The OP's way: 9 8 7 6 5 4 3 2 1 0иThe Garry_G way: 10 9 8 7 6 5 4 3 2 1
Anthony 15.12.2017 18:33:22
Это не делает то же самое. Переместите ваш x=x-1раньше, printfтогда вы можете сказать, что он делает то же самое.
CITBL 5.01.2019 17:05:49

Традиционным образом мы определяем условие в whileскобках цикла ()и условие завершения внутри фигурных скобок {}, но -->определяем оба сразу.

Например:

int abc(void)
{
    int a = 5
    while((a--) > 0) // Decrement and comparison both at once
    {
        // Code
    }
}

Это уменьшает aи запускает цикл, пока aбольше, чем 0.

Условно это будет выглядеть так:

int abc(void)
{
    int a = 5;
    while(a > 0)
    {
        a--;
        // Code
    }
    a--;
}

В обоих направлениях мы делаем одно и то же и достигаем одинаковых целей.

26
15.06.2019 19:35:13
Это неверно Код в вопросе: «test-write-execute» (сначала протестируйте, запишите новое значение, выполните цикл), ваш пример - «test-execute-write».
v010dya 14.07.2017 19:07:40
@ v010dya Исправлен ответ, теперь он test-write-executeкак в вопросе, спасибо за указание!
Vladislav Toncharov 12.05.2019 10:59:49
@VladislavToncharov Ваша правка все еще была неправильной. Смотри мой.
S.S. Anne 15.06.2019 19:36:17

(x --> 0) средства (x-- > 0)

  1. ты можешь использовать (x -->)
    output -: 9 8 7 6 5 4 3 2 1 0

  2. Вы можете использовать (-- x > 0) Это значит(--x > 0)
    output -: 9 8 7 6 5 4 3 2 1

  3. ты можешь использовать
(--\
    \
     x > 0)

output -: 9 8 7 6 5 4 3 2 1

  1. ты можешь использовать
(\
  \
   x --> 0)

output -: 9 8 7 6 5 4 3 2 1 0

  1. ты можешь использовать
(\
  \
   x --> 0
          \
           \
            )

output -: 9 8 7 6 5 4 3 2 1 0

  1. Вы также можете использовать
(
 x 
  --> 
      0
       )

output -: 9 8 7 6 5 4 3 2 1 0

Кроме того, вы можете попробовать много методов, чтобы успешно выполнить эту команду

7
23.09.2019 12:39:00

В этом контексте - и> два разных оператора. Оператор после увеличения имеет более высокий приоритет, чем оператор более. Поэтому оценка такова:

while((x--) > 0)
{
//TODO...
}
-1
29.04.2020 10:39:01