-2
#include <stdio.h>
#include <stdlib.h>
#define PATRAT(x) x*x+x;

int main()
{
    int x,y,z,t;

    x = 104;
    y = PATRAT(x - 1);
    z = PATRAT(y++);
    t = ++PATRAT(x);

     printf ("%d %d %d", y, z, t);

    return 1;
}

Given this code, the results are y = 105, z = 10506, t = 11130 and i can`t understand why. Can you please explain?

Cioby Andrei
  • 77
  • 1
  • 7
  • 2
    `PARAT(x - 1)` expands to `x - 1*x - 1 + x - 1` since `x = 104` this is `104 - 104 - 1 + 104 - 1` or `102` For `z` it's undefined behavior. – Iharob Al Asimi Feb 10 '16 at 17:15
  • 1
    What specifically don't you understand? – Emil Laine Feb 10 '16 at 17:15
  • 3
    Realize that `PATRAT` is *not* a true function. It's a preprocessor macro, and those only do textual substitution. Try writing out what the body of `main()` would look like if you expanded the macro invocations. – Steve Summit Feb 10 '16 at 17:17
  • I understood the first part with y why it becomes 102. But the result should be 103 since we have y++. – Cioby Andrei Feb 10 '16 at 17:17
  • 1
    Where did this code come from? Is it just an exercise? `t = ++PATRAT(x);` is a monstrosity. – lurker Feb 10 '16 at 17:17
  • 1
    It is not a function (as your title claims) but a macro – Basile Starynkevitch Feb 10 '16 at 17:19
  • z should be PATRAT(103) which is 10712 and t should be PATRAT(104) + 1 which is 10921 but the result is diffrent – Cioby Andrei Feb 10 '16 at 17:19
  • @lurker Yes, it is an exercise and i need to find what it returns. But what i am trying to do is to understand why it returns that – Cioby Andrei Feb 10 '16 at 17:21
  • @iharob The return value for y is 105, not 102 – Cioby Andrei Feb 10 '16 at 17:25
  • 1
    @CiobyAndrei It's UNDEFINED BEHAVIOR. – Iharob Al Asimi Feb 10 '16 at 17:27
  • Why do you say *`z` should be `PATRAT(103)`*? You don't know that because of the side effects of `y++` inside of the macro. As others have suggested, to understand the behavior of `PATRAT(y++)` you need to expand the macro, which occurs in line in the code. It's not like a function call at all. You'll find that `y++` occurs multiple times. So it's not the same result as, `w = y++; z = PATRAT(w);`. The expression `PATRAT(y++)` expands to, `y++*y+++y++` which the C compiler then compiles and which, among other things, is a mess. – lurker Feb 10 '16 at 17:28
  • 1
    Possible duplicate of [Why are these constructs (using ++) undefined behavior?](http://stackoverflow.com/questions/949433/why-are-these-constructs-using-undefined-behavior) – too honest for this site Feb 10 '16 at 17:32
  • @lurker I didn`t know how the fuction expands and i assumed it was that way but i understand now. So z should be 103 * 104 + 105 right? – Cioby Andrei Feb 10 '16 at 17:33
  • 2
    Not to belabor the point, but it's **not** a *function*. It's a *macro*. Big difference. And whether `z` *should be* `103 * 104 + 105` is not well-defined due to dependency when `++` occurs. This is the undefined behavior everyone is trying to explain. – lurker Feb 10 '16 at 17:36
  • 1
    @lurker I understand now, Thank you! – Cioby Andrei Feb 10 '16 at 17:37
  • Cool. That's the important part. :) – lurker Feb 10 '16 at 17:39

2 Answers2

3

Macro expansion.

If using GCC compile with -E to see the output after all includes and macros. Then it will become clear.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
  • I am using codeblocks, but i don`t know how to compile with -E. And i don`t need that, I need to understand why given that code, i get those results. I don`t know how that function works – Cioby Andrei Feb 10 '16 at 17:23
  • @CiobyAndrei What zan is suggesting is a method to expand the Macro and see the C pre processor output after that(not the final results).This would be the best method to see how the function actually works. – c_mnon Feb 10 '16 at 17:38
  • @c_mnon How do i use that method? – Cioby Andrei Feb 10 '16 at 17:40
  • @CiobyAndrei: Something like `gcc -E my-c-source-file.c` in a terminal window. – Zan Lynx Feb 10 '16 at 17:41
3

The preprocessor expands it as follows:

y = x - 1*x - 1+x - 1;;
z = y++*y+++y++;;
t = ++x*x+x;;

After we make that human-readable, it says:

y = x - (1 * x) - 1 + x - 1;
z = (y++ * y++) + y++;
t = (++x * x) + x;

Which is undefined behavior because we're modifying y without sequence points in between, so any output is possible.

Community
  • 1
  • 1
Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • 1
    Using `#define PATRAT(x) ((x)*(x)+(x));` will help with the first, by wrapping the argument and the whole expression in parentheses, but you **cannot** pass a pre- or post-increment parameter in to a macro and get reliable results. – TripeHound Feb 10 '16 at 17:29
  • Thank you! This is what i needed. But for z = PATRAT(y++) it would mean z = 103 * 104 + 105 and this result it is diffrent from 10506. @zenith – Cioby Andrei Feb 10 '16 at 17:30
  • I need to use the function the way it is @TripeHound – Cioby Andrei Feb 10 '16 at 17:32
  • @CiobyAndrei: The undefined behavior of incrementing more than once in an expression means that `y` might be the same value during all the operations, then have 3 added at the end. Or it might be y, y+1, y+2, or it might be y then have only 1 added at the end. It is UNDEFINED. – Zan Lynx Feb 10 '16 at 17:47
  • Sorry, but you cannot do that. Because it is a MACRO, not a function, it just expands the argument-TEXT as shown in the answer, giving something that is BY DEFINITION undefined. One compiler might give 103*103+103, another might give 105*105+105 _or any combination inbetween_. In fact, the same compiler might do it differently at different times. If you NEED to pass a ++ parameter, you MUST use a real function. – TripeHound Feb 10 '16 at 17:51
  • @ZanLynx I got it! Thank you! – Cioby Andrei Feb 10 '16 at 17:52
  • @TripeHound I was not trying to solve a problem with this Macro, this was an exercise and i had to tell what the result was and i didn`t know that that was a macro and how it works. – Cioby Andrei Feb 10 '16 at 17:53