2

In the following program, will repeated ~ and << operations converge to a negative value on all platforms?

#include <iostream>

int main()
{
    int x{};
    for(int i{}; i < 32; ++i) {
        x = ~x;
        x <<= 1;
        std::cout << x << '\n';
    }
}

My assessment is that it will because the left shift is not implementation defined. Would it be true to say that the only time it will not converge is if int is larger than 32 bits?

wally
  • 10,717
  • 5
  • 39
  • 72
  • What is `int i{}` supposed to mean? Or `int x{}` for that matter? An empty initializer list for an ordinal, vs `=0`, which is the default for that datatype, anyway? – 3Dave Jan 04 '17 at 21:20
  • 4
    Left shift of signed variables is undefined if it overflows. – Barmar Jan 04 '17 at 21:21
  • 4
    @DavidLively `int i{}` means value initialization. For a POD integer this means it will be initialized to 0. – wally Jan 04 '17 at 21:21
  • @Barmar Good point. But does it overflow in this case? – wally Jan 04 '17 at 21:22
  • `int`s are default-initialized to 0, and in 30 years of development this is the only time I've seen anyone use a `{}` on an ordinal type. Also, `{}` basically means "default initializer" MOST of the time, so it's useless. Thus concludes my rant. – 3Dave Jan 04 '17 at 21:22
  • @DavidLively - You'd prefer `int i = 0`? – Robᵩ Jan 04 '17 at 21:24
  • @Robᵩ I'd prefer it just be left off, but `int i = 0` is a lot more readable. But, I didn't mean to start an argument in the comments. Cheers. – 3Dave Jan 04 '17 at 21:24
  • @DavidLively the empty braces are [not an initializer list in this case](http://en.cppreference.com/w/cpp/language/value_initialization). Only if the type has no default constructor but has a constructor taking std::initializer_list will it perform list initialization. I truly want to avoid obfuscated code. For me this style has developed from consistent use of brace initialization wherever possible. Declared variables without an initializer become easier to see. – wally Jan 04 '17 at 21:31
  • @Robᵩ Which answer are you referring to? I see **Otherwise, if E1 has a signed type and non-negative value, and E1×2E^2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.** This question is creating a negative value when it does `~x`, then it shifts it. Shifting a negative is undefined. – Barmar Jan 04 '17 at 21:35
  • @Muscampester - yes, it overflows in the first iteration. `x = ~0; x<<=1;` overflows. – Robᵩ Jan 04 '17 at 21:35
  • Related: http://stackoverflow.com/questions/11644362/are-the-results-of-bitwise-operations-on-signed-integers-defined – Barmar Jan 04 '17 at 21:37
  • @Barmar - I misread that answer. – Robᵩ Jan 04 '17 at 21:38
  • @Barmar Undefined behavior it is then. Thanks for the answer. – wally Jan 04 '17 at 21:39
  • @David Lively `int i{}` is the sort of new stupidities that arrived with c++11, making the language ever more of a mess than it was already. – nikau6 Jan 04 '17 at 22:11

1 Answers1

0

My assessment is that it will because the left shift is not implementation defined.

The above statement is wrong. Left shift of a negative value is undefined behavior and the value is negative as soon as the bits of the initial zero value are inverted.


If the variable had been an unsigned integer then it would be fair to say that it will converge to a positive value on all compliant platforms (if enough of the bits are shifted):

#include <iostream>
#include <limits>

int main()
{
    unsigned short x{};
    for(int i{}; i < CHAR_BIT*sizeof(unsigned short); ++i) {
        x = ~x;
        x <<= 1;
        std::cout << x << '\n';
    }
}

Produces (on a 2's complement system):

65534
2
65530
10
65514
42
65450
170
65194
682
64170
2730
60074
10922
43690
43690
Community
  • 1
  • 1
wally
  • 10,717
  • 5
  • 39
  • 72