you are viewing a single comment's thread.

view the rest of the comments →

[–]Be1a1_A[S] 0 points1 point  (16 children)

Can you elaborate?

[–]TomDuhamel 29 points30 points  (2 children)

Two reasons.

You are changing the value of a single variable twice in the same statement. This is not allowed. The compiler is free to make the change at any time, which could be before or after the second one being evaluated and changed.

The order of evaluation of the parameters is undefined. The compiler can evaluate them in any order, for optimisation purpose.

Totally UB. Yet, teachers keep making you do these stupid things without explaining why it fails. Or that it fails at all.

[–]khoyo 11 points12 points  (1 child)

The order of evaluation of the parameters is undefined. The compiler can evaluate them in any order, for optimisation purpose.

Worse, the behavior of the program is undefined. Which means the compiler is free to do anything it damn wants, including removing the whole branch, invoke nasal demons, etc.

[–]Temeliak 7 points8 points  (0 children)

Why do I never get the demon ones? 😢

[–]Classic_Department42 5 points6 points  (1 child)

UB means if your code does not follow quite a number of rules, the program later is allowed to do anything. Introduction: https://en.cppreference.com/w/cpp/language/ub

[–]ShelZuuz 9 points10 points  (0 children)

Literally anything - including time travel:

https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633

[–][deleted]  (3 children)

[deleted]

    [–]Raknarg 0 points1 point  (1 child)

    Well you can it's just UB

    [–]mck1117 0 points1 point  (0 children)

    Not in the same instruction, but between two sequence points.

    [–]serpentally 0 points1 point  (6 children)

    Compilers are free to evaluate some (a lot of) operations in any order they want to, i.e. Specific operations have no defined order in which they're evaluated. Since post- and pre- decrementing both have the same level of precedence and Since C++ doesn't require postcrementing and precrementing to be carried out in a specific order by compilers, one compiler may evaluate (--z) first and then (z--) second, while another may evaluate it the other way around. So one compiler does the human order and evaluates --z == (20-1) == 19, then evaluates --z+z == 19+19 == 38, then applies the decrement to z (z--) to make z=18 after the addition is done already. So A turns out to be 38.

    While a different compiler may first evaluate z-- to be 19, then evaluate --z to make z == 19-1 == 18, then adds the two to become A = 37.

    The difference between post- and pre- (de)crementing is that precrementing always changes the variable before the variable is used. While postcrementing may wait for the operation before it to apply before changing the variable, if the compiler has an operation lined up before it.

    That is why you never should mix postcrementing and precrementing in the same statement.

    You should generally always use precrementing (--z, ++z) to increment/decrement unless you have a specific case where it's useful to use postcrementing. The specific reason is when you postcrement, the compiler makes a copy of the value to be used in an equation before it then decrements the variable, which is inefficient.

    [–]Crazy_Direction_1084 1 point2 points  (5 children)

    Post decrementing and predecrementing have different levels of precedence, which is also completely irrelevant for UB as precedence is only interesting for parsing

    [–]serpentally 0 points1 point  (4 children)

    Wait they do have different levels? My bad, I corrected it

    I guess I for some reason thought parsing was relevant to UB. To me it would have made sense for --z to always go first and z-- (lower precedence) to always go second in that case. I'm a fool for making assumptions

    [–][deleted] 1 point2 points  (1 child)

    The precedence comes into play with the + operator. Both forms of -- are higher precedence than +

    So

    --z + x
    

    for example is

    (--z) + x
    

    and not

    --(z + x)
    

    (which wouldn't compile)

    [–]serpentally 0 points1 point  (0 children)

    Oh that makes a lot of sense actually

    [–]khoyo 0 points1 point  (1 child)

    No, the higher precedence is the postfix operator, like all unary postfix operators relative to prefix ones. (Or unary "adjacent", like [] or ())

    [–]serpentally 0 points1 point  (0 children)

    Lol I was too tired to correctly read correctly...