Невозможно понять вывод программы на C

EDIT: этот вопрос не повторяется, поскольку в этом случае поведение не является неопределенным.

Почему приведенная ниже программа выводит вывод как 231 в первой строке?

У меня есть два сомнения по этому поводу:

  1. Поскольку я делаю постфиксное приращение, значение x не должно было увеличиваться до того, как я вызываю функцию max. Таким образом, на мой взгляд, вывод должен был быть 1 вместо 2. Что мне не хватает?

    #define prn(a) printf("%d",a)
    #define print(a,b,c) prn(a), prn(b), prn(c)
    #define max(a,b)  (a<b)? b:a
    
    main()
    {
        int x=1, y=1;
        print(max(x++,y),x,y);
        printf("\n");
        print(max(x++,y),x,y);
    }
    

    Выход:

    231
    451
    
  2. Постфиксная операция происходит после выполнения оператора? Рассмотрим пример ниже.

    int main()
    {
        int x = 0, y = 1;
        int a = x++ /*x is incremented hereafter?*/+ y;             // line 1
        /* Or x is incremented now after execution of above line?*/ // line 2
        int b = 0;
    }
    

person Michelle    schedule 13.10.2018    source источник
comment
2) Да, выполняется после инструкции, или, говоря более технически, инструкция увеличивает значение и возвращает значение до приращения, см. cpreference.   -  person KamilCuk    schedule 13.10.2018
comment
Я не думаю, что этот вопрос дублируется, потому что мой код просто вызывает максимальную директиву предварительной обработки, а не некоторые приращения и назначения одной и той же переменной самой себе. Пожалуйста, пересмотрите.   -  person Michelle    schedule 13.10.2018
comment
1) Расширение макроса происходит до выполнения таких конструкций, как x++. Итак, сначала компилятор заменил print(max(x++,y),x,y); и расширил до prn((x++<y) ? y:x++), prn(x), prn(y), а затем до printf("%d",(x++<y)? y:x++), printf("%d",x), printf("%d",y);. Затем выполняется строка get, первый printf печатает 2, x++<y ? y:x++ - первая проверка возвращает false, затем происходит первый x++, затем оператор возвращает 2 и снова увеличивает x++. Затем код печатает 3, так как x было увеличено дважды. Второй print(max...) делает то же самое.   -  person KamilCuk    schedule 13.10.2018
comment
@YuHao Можете ли вы объяснить, почему этот код UB? Код расширяется до printf("%d",(x++<y)? y:x++), printf("%d",x), printf("%d",y), и это не UB, ? отмечает точку последовательности, как C11 6.5.15p4.   -  person KamilCuk    schedule 13.10.2018
comment
@KamilCuk по второму вопросу вы имеете в виду, что приращение происходит в строке 1, верно?   -  person Michelle    schedule 13.10.2018
comment
Два приращения происходят в первой части строки 1.   -  person KamilCuk    schedule 13.10.2018
comment
Посмотрите на код после расширения. printf("%d",(x++<y)? y:x++) проверит, если x++<y ложно, потому что (x=1, y=1), он выполнит x++, т.е. x=2, потому что ? — это точка следования. Затем он оценит второе выражение после :, т.е. x++ - таким образом вернуть 2 и увеличить x=3. Тогда это будет printf("%d", 2). Второй prinf("%d", x) напечатает 3. Может быть, вы видите ? оператор.   -  person KamilCuk    schedule 13.10.2018
comment
@KamilCuk Просто для ясности во втором примере значение x увеличивается на единицу после того, как компилятор видит x++ в самой строке 1, но использует значение x = 0 для вычисления a и добавляет к нему y, верно?   -  person Michelle    schedule 13.10.2018
comment
@KenWhite Здесь нет неопределенного поведения.   -  person Michelle    schedule 13.10.2018
comment
@KenWhite Я не говорил, что это неправильно, может быть, вы меня неправильно поняли. Я спрашивал, почему так?   -  person Michelle    schedule 13.10.2018
comment
@ Мишель, этот вопрос не дублируется, поскольку поведение предварительного и постинкрементного приращения с #define нигде не упоминается. Вы можете взглянуть на мой ответ.   -  person Ganesh Chowdhary Sadanala    schedule 13.10.2018
comment
Оператор ?: имеет точку последовательности, поэтому первое приращение x должно быть выполнено до x++ после :.   -  person M.M    schedule 13.10.2018


Ответы (1)


позвольте мне взять эту линию

               print(max(x++,y),x,y);

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

Все директивы предварительной обработки начинаются с символа #. Например,

                #define PI 3.14

говорит компилятору заменить значение PI на 3.14 везде, где он увидит.

           c source code->preprocessor->compiler

поэтому print(max(x++,y),x,y) расширяется в макросе до

           1.      prn((x++<y) ? y:x++), prn(x), prn(y) 

        2. printf("%d",(x++<y)? y:x++), printf("%d",x), printf("%d",y);.

здесь он обрабатывается, вы можете внимательно проверить две вещи здесь

при проверке

               x++<y ,the x++ value is 1

затем после этого значение x становится равным 2

поэтому 2 печатается

а затем при печати мы также написали x++, что означает здесь x++ ЗНАЧЕНИЕ 2, но

после этого значение x равно 3

поэтому 3 печатается, а за y следует 1

вот как это работает

2. ЧТОБЫ дать вам отличное представление о преинкременте и постинкременте

позвольте мне взять пример

               int x=2;//value of x is 2

               x++;//here x++ value is 2

после выполнения этой строки значение x изменилось на 3

               ++x//here x++ value is 4 and also x value is 4.
person Ganesh Chowdhary Sadanala    schedule 13.10.2018
comment
Спасибо за ответ. Просто чтобы прояснить код во втором вопросе, значение x увеличивается в строке 1, верно? - person Michelle; 13.10.2018
comment
NO значение здесь int a =x++;//значение x++ равно 0, поэтому 0 присваивается a - person Ganesh Chowdhary Sadanala; 13.10.2018
comment
@Michelle Но значение x после этой строки становится равным 1, это то, что мы говорим как приращение сообщения. - person Ganesh Chowdhary Sadanala; 13.10.2018