Find The Bug

D

David Rasmussen

I have this code:

#include <iostream>

using namespace std;

#define DeclareEnumTricks(T) \
inline T& operator++(T& e) \
{ \
e = T(e+1); \
return e; \
} \
\
inline T operator++(T& e, int) \
{ \
T old = e; \
e = T(e+1); \
return old;\
} \
\
inline T& operator--(T& e) \
{ \
e = T(e-1); \
return e; \
} \
\
inline T operator--(T& e, int) \
{ \
T old = e; \
e = T(e-1); \
return old; \
} \
\
inline T end(T) \
{ \
return T##_end; \
} \
\
inline T begin(T) \
{ \
return T##_begin; \
}

enum Piece {none,pawn,knight,bishop,rook,queen,king,
Piece_begin = pawn, Piece_end = king + 1};
DeclareEnumTricks(Piece)

int main()
{
Piece p = none;
cout << p << " " << p++ << " " << ++p << endl;
}

The output from g++ and several other compilers is _not_

0 0 2

as expected. In g++ it is

2 1 1

Is there a bug in the code, or in the compilers?

/David
 
S

Sumit Rajan

David Rasmussen said:
I have this code:

#include <iostream>

using namespace std;

#define DeclareEnumTricks(T) \
inline T& operator++(T& e) \
{ \
e = T(e+1); \
return e; \
} \
\
inline T operator++(T& e, int) \
{ \
T old = e; \
e = T(e+1); \
return old;\
} \
\
inline T& operator--(T& e) \
{ \
e = T(e-1); \
return e; \
} \
\
inline T operator--(T& e, int) \
{ \
T old = e; \
e = T(e-1); \
return old; \
} \
\
inline T end(T) \
{ \
return T##_end; \
} \
\
inline T begin(T) \
{ \
return T##_begin; \
}

enum Piece {none,pawn,knight,bishop,rook,queen,king,
Piece_begin = pawn, Piece_end = king + 1};
DeclareEnumTricks(Piece)

int main()
{
Piece p = none;
cout << p << " " << p++ << " " << ++p << endl;
}

The output from g++ and several other compilers is _not_

0 0 2

as expected. In g++ it is

2 1 1

Is there a bug in the code, or in the compilers?

/David


Comeau C++ came up with the expected output: 0 0 2
 
P

Pete Becker

Sumit said:
Comeau C++ came up with the expected output: 0 0 2

Doesn't matter what's expected. What matters is what's required. The
behavior of the program is undefined. Anything goes.
 
D

David Rasmussen

osmium said:
David Rasmussen writes:



Did you allow for the fact that shift left has a lower precedence than
postfix ++ and prefix ++?

Even if, the first p should print out as 0. Shouldn't it?

/David
 
D

David Rasmussen

Pete said:
Doesn't matter what's expected. What matters is what's required. The
behavior of the program is undefined. Anything goes.

I would sure like to know why...

/David
 
D

David Rasmussen

Thanks!

I don't know what I was thinking. I know about the sequencing point type
problem. My mind was focused on the macros. I was sure I had some bug.

/David
 
K

Kevin Goodsell

David said:
Thanks!

I don't know what I was thinking. I know about the sequencing point type
problem. My mind was focused on the macros. I was sure I had some bug.

Where is there a sequence point problem?

-Kevin
 
R

Ron Natalie

David Rasmussen said:
cout << p << " " << p++ << " " << ++p << endl;
}

The output from g++ and several other compilers is _not_

0 0 2

as expected. In g++ it is

2 1 1

Is there a bug in the code, or in the compilers?
In the code. You have undefined behavior. You modify p multiple
times between sequence point for certain allowable orderings.
 
R

Ron Natalie

Pete Becker said:
Doesn't matter what's expected. What matters is what's required. The
behavior of the program is undefined. Anything goes.
Not undefined, it's just that his operators are invoked in an unspecified order.
Remember there are overloads for the operator++.
 
R

Ron Natalie

David Rasmussen said:

Argument evaluation order is not fixed in C++. The order of evaluating:
the three subexpressions "p", "p++" and "++p" is unspecified. Might happen
left to right, my happen right to left, might happen in any order. All you know
is that they happen before their respective << operators (but no guarantee
with respect to each other).
 
R

Ron Natalie

Ron Natalie said:
In the code. You have undefined behavior. You modify p multiple
times between sequence point for certain allowable orderings.

BZZT. Caught myself here. Not undefined behavior as there are inherent
sequence points in the function calls. operator ++ is overloaded here.
 
P

Pete Becker

David said:
Even if, the first p should print out as 0. Shouldn't it?

Nope. The behavior of the code is undefined, so there's nothing it
"should" do. I can't tell from your messages whether you've seen what
the problem is. Here's a simpler version:

cout << i++ << i++;

The code modifies the value of i twice without an intervening sequence
point.
 
R

Ron Natalie

Pete Becker said:
cout << i++ << i++;

The code modifies the value of i twice without an intervening sequence
point.

No it does not. The ++ operators are overloads. There are sequence points
before and after the modification (the ones inherent in calling and returning from
functions).

His only sin is to expect that function arguments are to be evaluated in some particular
order.
 
J

Jonathan Turkanis

Ron Natalie said:
No it does not. The ++ operators are overloads. There are sequence points
before and after the modification (the ones inherent in calling and returning from
functions).

His only sin is to expect that function arguments are to be evaluated in some particular
order.

I made the same mistake above.

Jonathan
 
P

Pete Becker

Ron said:
Not undefined, it's just that his operators are invoked in an unspecified order.
Remember there are overloads for the operator++.

Where is the sequence point between the two increments?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top