Member 13035169 Ответов: 4

Не понимая основной проблемы C


Я ожидаю, что ответ должен прийти как 1.но в компиляторе GCC и Turbo C компилятор показывает результат как 0.In какой-то компилятор DEV c показывает результат как 1.Какой из них правильный и почему ?

#include<stdio.h>
int main()
{
   int z = 0;
   z = 0 || z++;
   printf ("%d", z);
   return 0;
 }


Что я уже пробовал:

Я пробовал в Dev c , GCC и Turbo C компиляторе.

Suvendu Shekhar Giri

Заголовок вашего вопроса не должен содержать фрагментов кода / всей программы.

[no name]

- > какой из них правильный и почему ?
Пожалуйста, объясните словами алгоритм, который вы реализуете с помощью этого кода. Этот код имеет Неопределенное поведение[^]

4 Ответов

Рейтинг:
2

Jochen Arndt

У вас есть логическое Оценка короткого замыкания - Википедия[^] операция формы

a || b

Логический результат первого выражения
z = 0

это значение левого операнда z после задания. Когда это значение равно нулю, логический результат равен false. Вы можете проверить это:
int z = 0;
int a = (z = 0) ? 1 : 0;
int b = (z = 1) ? 1 : 0;
printf("%d %d\n", a, b);

Это должно печатать 0 1 со всеми компиляторами.

После того, как логический результат левого члена был вычислен, вторая операция должна быть выполнена только тогда, когда первая была истинной:
int b = (z = 0) ? 1 : 0;
if (b)
    b = (z++) ? 1: 0;

Затем z будет по-прежнему равен нулю, потому что операция приращения не выполняется.
[EDIT2]
Вышесказанное неверно (спасибо Н. в.)!
Он должен быть сбит с курса, если (!b)
[/EDIT2]

Таким образом, компиляторы, выполняющие всегда вторую операцию, могут не соответствовать стандарту C. Я написал "Может быть", потому что не совсем уверен в этом особом случае, когда логический результат не используется.

Вы можете проверить это таким образом (все оптимизации отключены; например,- O0 с GCC):
if (z = 0 || z++)
    printf("true: %d\n", z); // Never reached
else
    printf("false: %d\n", z); // Always executed

Компилятор, который печатает здесь "1", не соответствует стандарту Си.

[РЕДАКТИРОВАТЬ]
Обратите внимание также, что оптимизирующие компиляторы могут обнаружить, что результат логической операции всегда ложен, и присвоить ему ноль. z или даже пропустить строчку
z = 0 || z++;
потому что z уже был установлен на ноль в предыдущей строке.
[/РЕДАКТИРОВАТЬ]

[EDIT2]
Решение 3 указывает на проблему.
Поведение не определено, как указано в предупреждении.
Попробовать это:
int z = 0;
z = 0 || z++;
printf ("z: %d\n", z);

(z = 0) || (z++);
printf ("z: %d\n", z);

С помощью GCC он будет печатать
z: 0
z: 1

[/EDIT2]


[no name]

-> ' Это должно печатать 0 1 со всеми компиляторами.'?

Jochen Arndt

Результатом операции присваивания является значение левого операнда после присваивания.
Логический результат - это значение, равное нулю или нет.
В C++ или C99 с stdbool.h:
bool a = (z = 0); / / всегда false
bool b = (z = 1); / / всегда истинно

[no name]

Мне очень жаль, что я неправильно истолковал это заявление. Это отличное объяснение.

Рейтинг:
2

CPallini

gcc -Wall mytest.c
mytest.c: In function ‘main’:
mytest.c:6:7: warning: operation on ‘z’ may be undefined [-Wsequence-point]
     z = 0 || z++;
То есть вы попали в темный угол C алгоритмический язык. Смотрите, например Точка последовательности-Википедия[^].
В качестве примечания, включающего все предупреждения (-Wall с gcc может оказаться полезным, в конце концов).


Рейтинг:
1

Patrice T

вы находитесь в серой зоне, потому что компилятор C может переписать ваш код для оптимизации.
Эта линия непредсказуема:

z = 0 || z++;

Потому что у вас есть постинкремент на переменную, которая используется 2 раза в строке.
вы получаете 0, когда код переводится в:
tmp = 0 || z;
z++;
z=tmp;

вы получаете 1, когда код переводится в:
tmp = 0 || z;
z=tmp;
z++;

Это зависит от компилятора.


Рейтинг:
0

nv3

Чего вы ожидали от этих заявлений:

int z = 0;
z = 0 || z++;

Это снова вопрос о том, выполняется ли постинкремент до или после присвоения z.


Jochen Arndt

Речь идет об оценке короткого замыкания, и приращение никогда не должно выполняться.

nv3

Привет, Йохен! Я действительно не согласен. Поскольку первый операнд (0) является ложным, второй операнд (z++) должен быть вычислен, и результат выражения всегда равен 0.

Фактический вопрос заключается в следующем: будет ли пост-декремент выполнен до или после назначения z. В первом случае выполняется постинкремент до z, затем результат выражения (0) присваивается z-таким образом, перезаписывается эффект постинкремента. Во втором случае сначала выполняется присвоение, а затем постинкремент будет впоследствии увеличивать z до значения 1.

Насколько мне известно, стандарт C не ясен в тот момент, когда будет выполняться постинкремент. И признаюсь, лично мне все равно. Никто в здравом уме не напишет подобное утверждение в производственном коде. Таким образом, снова один из этих вопросов, которые являются чисто академическими.

Jochen Arndt

Вы правы!
Глупая ошибка (это операция или).

Я обновлю свое решение.

nv3

Это случается с лучшими из нас :-)