Поведение оператора инкремента сообщения [дубликат]

16
задан Community 23 May 2017 в 12:19
поделиться

10 ответов

Это - пример неуказанного поведения. Стандарт делает не , говорят, в чем должны быть оценены аргументы порядка. Это - решение реализации компилятора. Компилятор является бесплатным оценить аргументы функции в любом порядке.

В этом случае, это похоже, на самом деле обрабатывает аргументы справа налево вместо ожидаемого слева направо.

В целом, выполнение побочных эффектов в аргументах является плохой практикой программирования.

Вместо нечто (тестируют ++, тест); необходимо записать нечто (тест, test+1); тест ++;

Это было бы семантически эквивалентно тому, что Вы пытаетесь выполнить.

Редактирование: Как Anthony правильно указывает, это не определено, чтобы и считать и изменить единственную переменную без прошедшей точки последовательности. Так в этом случае поведение действительно не определено . Таким образом, компилятор является бесплатным генерировать безотносительно кода он хочет.

47
ответ дан 30 November 2019 в 15:02
поделиться

Это не всего неуказанное поведение, это на самом деле неопределенное поведение .

Да, порядок оценки аргумента неуказанный , но это не определено , чтобы и считать и изменить единственную переменную без прошедшей точки последовательности, если чтение не только в целях вычисления нового значения. Нет никакой точки последовательности между оценками аргументов функции, таким образом f(test,test++) неопределенное поведение : test читается из одного аргумента и изменяется для другого. При перемещении модификации в функцию тогда, Вы в порядке:

int preincrement(int* p)
{
    return ++(*p);
}

int test;
printf("%d %d\n",preincrement(&test),test);

Это вызвано тем, что существует точка последовательности на входе и выходе к preincrement, таким образом, вызов должен быть оценен или прежде или после простого чтения. Теперь порядок всего неуказанный .

Примечание также, что оператор запятой обеспечивает точку последовательности, таким образом

int dummy;
dummy=test++,test;

прекрасный---, инкремент происходит перед чтением, таким образом dummy установлен на новое значение.

29
ответ дан 30 November 2019 в 15:02
поделиться

Все, что я сказал первоначально, НЕПРАВИЛЬНО! Момент времени, в котором влияние стороны вычисляется , неуказанный. Visual C++ выполнит инкремент после вызова к нечто (), если тест будет локальной переменной, но если тест будет объявлен как статичный или глобальный, то это будет увеличено перед вызовом к нечто () и приведет к различным результатам, хотя окончательное значение теста будет корректно.

инкремент должен действительно быть сделан в отдельном операторе после вызова к нечто (). Даже если бы поведение было определено в стандарте C/C++, то это сбивало бы с толку. Вы думали бы, что компиляторы C++ отметят это как потенциальную ошибку.

Здесь хорошее описание точек последовательности и неуказанного поведения.

<----ЗАПУСТИТЕ НЕПРАВИЛЬНОЙ НЕПРАВИЛЬНОЙ НЕСПРАВЕДЛИВОСТИ---->

"++", бит "теста ++" выполняется после вызова к нечто. Таким образом, Вы передаете в (0,0) нечто, не (1,0)

Вот является ассемблерный вывод из Visual Studio 2002:

mov ecx, DWORD PTR _i$[ebp]
push    ecx
mov edx, DWORD PTR tv66[ebp]
push    edx
call    _foo
add esp, 8
mov eax, DWORD PTR _i$[ebp]
add eax, 1
mov DWORD PTR _i$[ebp], eax

инкремент сделан ПОСЛЕ вызова к нечто (). В то время как это поведение дизайном, это, конечно, сбивает с толку случайного читателя и должно, вероятно, избежаться. Инкремент должен действительно быть сделан в отдельном операторе после вызова к нечто ()

<----КОНЕЦ НЕПРАВИЛЬНОЙ НЕПРАВИЛЬНОЙ НЕСПРАВЕДЛИВОСТИ---->

14
ответ дан 30 November 2019 в 15:02
поделиться

Это - "неуказанное поведение", но на практике с путем стек вызовов C определяется, это почти всегда гарантирует, что Вы будете рассматривать его как 0, 0 и никогда 1, 0.

, Поскольку кто-то отметил, ассемблер, произведенный VC, продвигает право большая часть параметра на стеке сначала. Это - то, как вызовы функции C реализованы в ассемблере. Это должно разместить C "бесконечный список параметров" функция. Путем продвижения параметров в справа налево порядке, первый параметр, как гарантируют, будет главным объектом на стеке.

Берут подпись printf:

int printf(const char *format, ...);

Те замещающие знаки обозначают неизвестное количество параметров. Если бы параметры были продвинуты слева направо, формат был бы у основания стека, которого мы не знаем размера.

Знание, что в C (и C++), что параметры обрабатываются слева направо, мы можем определить самый простой способ проанализировать и интерпретировать вызов функции. Доберитесь до конца списка параметров и начните продвигать, оценив любые сложные операторы, когда Вы идете.

Однако даже это не может сохранить Вас, поскольку большинство компиляторов C имеет опцию проанализировать функции "стиль Паскаля". И все это означает, то, что параметры функции продвинуты на стеке в слева направо вид. Если бы, например, printf был скомпилирован с опцией Pascal, то вывод, скорее всего, был бы 1, 0 (однако, так как printf использует эллипс, я не думаю, что это может быть скомпилированный стиль Паскаля).

6
ответ дан 30 November 2019 в 15:02
поделиться

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

более безопасно записать нечто (тест, тест + 1) и затем сделать ++ тест в следующей строке. Так или иначе компилятор должен оптимизировать его, если это возможно.

2
ответ дан 30 November 2019 в 15:02
поделиться

Компилятор не мог бы оценивать аргументы в порядке, который Вы будете ожидать.

1
ответ дан 30 November 2019 в 15:02
поделиться

Порядок оценки для аргументов функции не определен. В этом случае кажется, что это сделало их справа налево.

(Изменение переменных между точками последовательности в основном позволяет компилятору делать что-либо, которое оно хочет.)

1
ответ дан 30 November 2019 в 15:02
поделиться

Гм, теперь, когда OP был отредактирован для непротиворечивости, это вне синхронизации с ответами. Фундаментальный ответ о порядке оценки корректен. Однако определенные возможные значения отличаются для нечто (++ тест, тест); случай.

++ тест будет быть увеличенным прежде чем быть переданным, таким образом, первый аргумент всегда будет 1. Второй аргумент будет 0, или 1 в зависимости от порядка оценки.

1
ответ дан 30 November 2019 в 15:02
поделиться

Согласно стандарту C, это - неопределенное поведение иметь больше чем одну ссылку на переменную в единственной точке последовательности (здесь, можно думать об этом как являющемся оператором или параметрами к функции), где одна из большего количества тех ссылок включает пред/сообщение модификация. Так: нечто (f ++, f) < - неопределенный относительно того, когда f увеличивает. И аналогично (я вижу это все время в пользовательском коде): *p = p ++ + p;

Обычно компилятор не изменит свое поведение для этого типа вещи (за исключением главных версий).

Избегают его путем включения предупреждений и уделения внимания им.

1
ответ дан 30 November 2019 в 15:02
поделиться

Для повторения, что сказали другие это - весьма указанное поведение, а скорее неопределенный. Эта программа может по закону произвести что-либо или ничто, оставить n в любом значении или послать оскорбительное электронное письмо Вашему боссу.

Как практику, разработчики компилятора будут обычно просто делать то, что является самым легким для них записать, который обычно означает, что программа выберет n несколько раз, вызовет функцию и увеличит когда-то. Это, как любое другое мыслимое поведение, очень хорошо согласно стандарту. Нет никакой причины ожидать то же поведение между компиляторами или версии, или с различными параметрами компилятора. Нет никакой причины, почему два различных, но подобно выглядящих примера в той же программе должны последовательно компилироваться, хотя это - способ, которым я держал пари.

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

1
ответ дан 30 November 2019 в 15:02
поделиться