1

If I do something like this:

static int counter = 0;
counter = std::min(8, counter++);

I get a warning with g++ saying:

operation on 'counter' may be undefined [-Wsequence-point]

This works fine:

static int counter = 0;
counter++;
counter = std::min(8, counter);

Results are the same with ++counter and/or std::max.

I can't work out what's wrong with the first version. This also occurs with std::max. Just for an example, I get no warning when using functions from GLM.

Can anyone explain this a little bit for me? I'm using GCC 4.8 on Ubuntu 14.04.

EDIT: A bit more testing (which I should have done first) If I do cntr = std::min(8, ++cntr);, as I am in my actual application, printing the value after this line results in 1, then 2, then 3, etc. HOWEVER, if I do cntr = std::min(8, cntr++);, the vaule is 0 EVERY TIME, it never increases at all.

Jagoly
  • 939
  • 1
  • 8
  • 32
  • 1
    No, sorry. I use the name cntr in my actual code, but changed it here for example purposes. I missed some though out of habit. – Jagoly Dec 12 '14 at 12:04
  • @Jagoly be careful when posting codes xP that mistake cost me a -1 lol –  Dec 12 '14 at 12:05
  • 1
    possible duplicate of [Undefined Behavior and Sequence Points](http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points) – Barry Dec 12 '14 at 12:07
  • 1
    @Barry: Except, as far as I can see, the increment should be sequenced before the function call, and the assignment after. By my reading of C++11 5.2.6/1 and 5.17/1, there's no UB here and the compiler is wrong. Or if it's right, the reason is quite subtle (perhaps because the function takes reference arguments so there's no lvalue-to-rvalue conversion?) – Mike Seymour Dec 12 '14 at 12:14
  • @MikeSeymour: It is strange that he doesn't get the warning when using glm::max, which also takes reference arguments. – odyss-jii Dec 12 '14 at 12:20
  • @MikeSeymour from 1.19/15 "When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function. [ Note: Value computations and side effects associated with different argument expressions are unsequenced. —end note ]" – Barry Dec 12 '14 at 12:23
  • @Barry: The note says the side effects of **different argument expressions** are unsequenced (relative to each other). The normative text says that all of them are sequence before the function call. – Mike Seymour Dec 12 '14 at 12:25
  • @MikeSeymour I think you're correct. – Barry Dec 12 '14 at 12:34

1 Answers1

0

I think Mike Seymour's comment is correct - there should be no UB because the function argument expressions should be sequenced before the function call. From 1.19/15:

When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function.

So gcc is probably incorrect. Note also that in some other cases, the warnings don't show up:

int f(int a, int b);
template <typename T> T g(T a, T b);
template <typename T> const T& h(const T& a, const T& b);

counter = f(8, counter++); // no warning
counter = g(8, counter++); // no warning
counter = h(8, counter++); // gcc gives warning - there should be nothing special
                           // about h as compared to f,g... so warning is likely
                           // incorrect

clang gives no warning on any of these.

Given that the function arguments are sequenced before the call, that explains why this:

int counter = 0;
counter = std::min(8, counter++);

Always returns 0. That code is equivalent to:

counter = 0;

int a1 = 8;         // these two can be evaluated in either order
int a2 = counter++; // either way, a2 == 0, counter == 1

counter = std::min(a1, a2); // which is min(8, 0) == 0.
Barry
  • 286,269
  • 29
  • 621
  • 977
  • So, from my understanding now, neither option should give actually give a warning (or at least not this one)? Thanks Barry and Mark for the info. I wonder if any other compilers do this, or even gcc4.9. – Jagoly Dec 12 '14 at 12:58
  • @Jagoly That's my understanding. gcc4.9 does give a warning on this code too. – Barry Dec 12 '14 at 13:05
  • Accepted your answer, as it seems to summarise your discussion with mike pretty well. – Jagoly Dec 13 '14 at 06:58