1
//prog1.c    
#include <stdio.h>
    int f(int *a,int *b,int c) {
      if(c == 0) return 1;
      else {
        *a = *a + 1;
        *b = *b - 1;
         c =  c - 1;
         return (*a + f(a,b,c) + *b);
      }
    }
    int main() {
      int a = 3,b = 3,c = 3;
      printf("%d\n",f(&a,&b,c));
      return 0;
    }

I executed the program using gcc and clang-3.5 and found output = 16.

I think there might be some implementation specific behaviour like the follwoing code

//prog2.c
#include <stdio.h>
int f(int *x,int *y,int *z) {
  *x = *x + 1;
  *y = *y + 1;
  *z = *z + 1;
  return 0;
}
int main() {
  int a=0,b=0,c=0;
  printf("%d %d %d\n",a,f(&a,&b,&c),b);;
  return 0;
}
// gcc output : 1 0 0
// clang-3.5 :  0 0 1

In prog1.c is there any implementation specific behaviour in the return statement ? If not how is it evaluating ?

I may not know some kind of undefined behaviour Or, unspecified behaviour. Please explain. Thanks

Debashish
  • 1,155
  • 19
  • 34
  • 1
    See also [Is this undefined behaviour in C? If not, predict the output logically.](http://stackoverflow.com/questions/41775973) and (if you're a 10K user) [How the given C code works?](http://stackoverflow.com/questions/41775508/how-the-given-c-code-works) — now deleted. – Jonathan Leffler Jan 21 '17 at 06:44
  • 1
    Both programs depend on the order in which the terms of the expressions are evaluated, and that order is not mandated by the C standard. In the second example, the outputs from both GCC and Clang are acceptable; they're even fairly easily explained. But you can't rely on getting either result — or even on getting one of the two results (other results are also possible). – Jonathan Leffler Jan 21 '17 at 06:51
  • 1
    You've been given and have accepted erroneous answers. – Jonathan Leffler Jan 21 '17 at 06:53
  • 1
    @JonathanLeffler There is undefined behaviour here , right ? –  Jan 21 '17 at 06:54
  • 3
    @pC_; Yes. This is very similar to the question you asked and a [deleted one](http://stackoverflow.com/q/41775508/2455888). Is this a homework or what? 3 similar questions back to back! – haccks Jan 21 '17 at 06:56
  • 1
    @pC_: Indeed; very much so. The `prog1.c` example is almost identical to the deleted question — that used the value 2 instead of 3 for the initial values. It has more complicated undefined behaviour than your code did having two pointer variables instead of just one. – Jonathan Leffler Jan 21 '17 at 06:56

2 Answers2

2

As noted in comments and in the near duplicate question (Is this undefined behaviour in C? If not, predict the output logically.), the results from both these programs are not fully defined by the C standard — they produce 'unspecified behaviour' because the order of evaluation of the terms in the return statement of the first and the printf() call in the second is not specified by the language and is at the whim of the compiler. (Note that it is 'unspecified behaviour' rather than formally 'undefined behaviour' — see the discussion in the comments. It is not 'implementation defined' behaviour either; the implementation is not required to document what it does.)

That means that the results given by any implementation are 'implementation specific' in the terms of the question. Different implementations may legitimately produce different answers.

The first program is:

#include <stdio.h>

int f(int *a,int *b,int c) {
  if(c == 0) return 1;
  else {
    *a = *a + 1;
    *b = *b - 1;
     c =  c - 1;
     return (*a + f(a,b,c) + *b);
  }
}

int main() {
  int a = 3,b = 3,c = 3;
  printf("%d\n",f(&a,&b,c));
  return 0;
}

The problematic part is return (*a + f(a,b,c) + *b); because *a could be evaluated before or after the recursive function call, and f() modifies the values that a and b point at so the order of evaluation matters. Different compilers could legitimately produce different results. The same compiler could produce different results at different times, or under different optimization flags, or as it chooses. Both *a and *b could be evaluated before the call, or after the call, or either one could be evaluated before and the other after — and that just names 4 plausible alternatives.

The second program is:

#include <stdio.h>
int f(int *x,int *y,int *z) {
  *x = *x + 1;
  *y = *y + 1;
  *z = *z + 1;
  return 0;
}
int main() {
  int a=0,b=0,c=0;
  printf("%d %d %d\n",a,f(&a,&b,&c),b);;
  return 0;
}

The problem is that the sequence in which a, f(&a, &b, &c) and b are evaluated for the call to printf() is not specified by the standard and you get different results depending on the sequence chosen by the compiler. You showed that GCC and Clang produce different results — both those results are acceptable according to the standard, and so are plenty of others.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    There is no undefined behaviour, there is a sequence point before and after a function call. It is unspecified behaviour. – M.M Jan 21 '17 at 07:23
  • @M.M — I'll reserve judgement on 'undefined' vs 'unspecified'; I've revised the text to avoid 'undefined behaviour'. – Jonathan Leffler Jan 21 '17 at 07:27
  • 1
    I recommend satisfying yourself that it is not undefined and then updating answer accordingly . This is a significant point because UB can launch missiles etc, whereas this program must output a number from a (possibly large) finite set of possibilities – M.M Jan 21 '17 at 07:28
  • 1
    @M.M; Standard says: *If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.* This makes the statement `return (*a + f(a,b,c) + *b);` of undefined behavior. – haccks Jan 21 '17 at 07:32
  • 1
    @M.M: I'm not doing it now — it's bedtime here. See the quotes from the standard in [haccks](http://stackoverflow.com/users/2455888/haccks) excellent [answer](http://stackoverflow.com/a/41776340/15168) to the closely related question. The quotes include the term 'undefined behaviour' for some of the issues. – Jonathan Leffler Jan 21 '17 at 07:32
  • 1
    @haccks see "unsequenced side effect" in your quote. There is no unsequenced side effect in OP's code, the function is sequenced – M.M Jan 21 '17 at 07:32
  • 1
    @haccks they are indeterminately sequenced, not unsequenced. See C11 6.5.2.2/10 – M.M Jan 21 '17 at 07:39
  • @JonathanLeffler; I looked into standard closely and concluded that M.M is right. I corrected my answer there. – haccks Jan 21 '17 at 09:36
  • The second example is also defined, and the result is just unspecified. The variables a,b,and c are not modified without enclosing sequence points. The possible orderings are: 1. a,b,sq,call,sq. 2. b,a,sq,call,sq. 3. b,sq,call,sq,a. 4. a,sq,call,sq,b. 5.sq,call,sq,a,b 6. sq,call,sq,b,a and neither of them causes undefined behavior. – 2501 Jan 21 '17 at 10:01
  • According to Robbert Krebber's [CH2O](http://http://robbertkrebbers.nl/research/ch2o/) tool, which calculates all possible behaviors of simple C programs, the possible outputs of the second example program are `0 0 0`, `0 0 1`, `1 0 0` and `1 0 1`. That also means that the program indeed does not have undefined behavior. – Freek Wiedijk Jan 21 '17 at 14:05
0

In prog1.c is there any implementation specific behaviour in the return statement ? If not how is it evaluating ?

There is nothing wrong about the return statement except that the recursive call would be endless if your original call to f with c is negative.

It's not clear the purpose of your function f - but the terminating condition should be better written as:

if(c <= 0) return 1;
artm
  • 17,291
  • 6
  • 38
  • 54