Sign in to follow this  
bikola_p

c++ inconsistency...really, look inside.

Recommended Posts

Why doesnt the macro equivilent of the Inline function act the same, the code is a replica. However, strange enough i get diff results. Here look.
#include <iostream>
using namespace std;

#define BAND(x) (((x)>5 && (x)<10) ? (x) : 0) //LOOK AT THIS LINE


int main() {
  for(int i = 4; i < 11; i++) {
    int a = i;
    cout << "a = " << a << endl << '\t';
    cout << "BAND(++a)=" << BAND(++a) << endl;
    cout << "\t a = " << a << endl;
  }
  return 0;
}

IN COMPARISON TO 

#include <iostream>
using namespace std;

inline band(int x) {return (x>5 && x<10)? x : 0;} //THIS LINE


int main() {
  for(int i = 4; i < 11; i++) {
    int a = i;
    cout << "a = " << a << endl << '\t';
    cout << "band(++a)=" << band(++a) << endl;
    cout << "\t a = " << a << endl;
  }
  return 0;
}
THE output of both programs are different, after follwoing the programs, the inline function is the correct one, what is wrong with macro's?

Share this post


Link to post
Share on other sites
The wrong thing about macros is, that they are only textual replacements.
In you case the line

cout << "BAND(++a)=" << BAND(++a) << endl;

is replaced by

cout << "BAND(++a)=" << (((++x)>5 && (++x)<10) ? (++x) : 0) << endl;


Share this post


Link to post
Share on other sites
oh lol, so its something that was around, i thought this discovery would make me famous like the pioneers..nah just playin, thanks for that though...

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
I'm pretty sure that the behaviour with the macro version isn't even (pardon the pun) defined.


Invoking the macro on its own with ++a is well defined -- logical operations and the ternary operation imply sequence points and have a well defined order.

Share this post


Link to post
Share on other sites
Quote:
Original post by Polymorphic OOP
Quote:
Original post by Zahlman
I'm pretty sure that the behaviour with the macro version isn't even (pardon the pun) defined.


Invoking the macro on its own with ++a is well defined -- logical operations and the ternary operation imply sequence points and have a well defined order.


Can you go into more detail? I never understood what would be defined behavior in cases like these and not.

Share this post


Link to post
Share on other sites
C++ has the concept of sequence points. A sequence point is basically a point in the code where everything before it has to have finished evaluating before execution proceeds any further. For example: the end of a statement is a sequence point. So this is well defined:
++a;
++a;

Even though this is not:
++a + ++a;


Another example is a function call: all arguments to the function call must be evaluated before the function is actually called. So if you have foo(++a, ++b), you know that both ++a and ++b were both evaluated before foo() was called.

Logical and and or, the ternary operator and the comma operator also have a sequence point after the first expression. So in A && B, A || B, A , B and A ? B : C the A has to finish evaluating, with all its side effects before B (or C) is evaluated. So ++a && ++a has well defined behaviour even though ++a + ++a</t> doesn't.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Another example is a function call: all arguments to the function call must be evaluated before the function is actually called. So if you have foo(++a, ++b), you know that both ++a and ++b were both evaluated before foo() was called.


Just to add one more: while you can be sure that they will be evaluated before the function call, you can't be sure about the order. So doing something like foo(a,++a) and relying on a left to right order isn't a good idea (and real fun to debug when differently optimized builds or builds from different compilers behave differently).

Share this post


Link to post
Share on other sites
Quote:
Original post by Trienco
Quote:
Original post by SiCrane
Another example is a function call: all arguments to the function call must be evaluated before the function is actually called. So if you have foo(++a, ++b), you know that both ++a and ++b were both evaluated before foo() was called.


Just to add one more: while you can be sure that they will be evaluated before the function call, you can't be sure about the order. So doing something like foo(a,++a) and relying on a left to right order isn't a good idea (and real fun to debug when differently optimized builds or builds from different compilers behave differently).


I'm assuming the order its evaluated is based on the calling convention of that function. I'm sure this isn't guarenteed in the standard but it makes sense from a compiler point of view.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
C++ has the concept of sequence points. A sequence point is basically a point in the code where everything before it has to have finished evaluating before execution proceeds any further. For example: the end of a statement is a sequence point. So this is well defined:
++a;
++a;

Even though this is not:
++a + ++a;


Another example is a function call: all arguments to the function call must be evaluated before the function is actually called. So if you have foo(++a, ++b), you know that both ++a and ++b were both evaluated before foo() was called.

Logical and and or, the ternary operator and the comma operator also have a sequence point after the first expression. So in A && B, A || B, A , B and A ? B : C the A has to finish evaluating, with all its side effects before B (or C) is evaluated. So ++a && ++a has well defined behaviour even though ++a + ++a</t> doesn't.


So, sequence points consist of
- ;
- ()
- &&
- ||
- ? :
- function call

All other operators are not a sequence point and do not guarentee the order of evaluations.

Anything I'm missing?

Share this post


Link to post
Share on other sites
Quote:
Original post by ph33r
Anything I'm missing?


Yes, the comma operator: ,

++a, ++a; is perfectly well defined.

Note that overloading &&, || or , turns them into a function call, changing the position of the sequence point ang producing undefined behaviour in the above examples.

Share this post


Link to post
Share on other sites
Quote:
Original post by ph33r
Quote:
Original post by Trienco
Quote:
Original post by SiCrane
Another example is a function call: all arguments to the function call must be evaluated before the function is actually called. So if you have foo(++a, ++b), you know that both ++a and ++b were both evaluated before foo() was called.


Just to add one more: while you can be sure that they will be evaluated before the function call, you can't be sure about the order. So doing something like foo(a,++a) and relying on a left to right order isn't a good idea (and real fun to debug when differently optimized builds or builds from different compilers behave differently).


I'm assuming the order its evaluated is based on the calling convention of that function. I'm sure this isn't guarenteed in the standard but it makes sense from a compiler point of view.


No, it might. If we have a function:
void func(int,int,int);
And we call it like this:
func(++a, ++b, ++c)
And the compiler pass parameters from left to right, it could do something like this:

inc a
inc b
inc c
push a
push b
push c

But there is no reason it couldn't call inc in the opposite order, especially if it determines that it might give a speedup to change the order (c might be in the cache so we should start incrementing c).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this