2

I need to port this Assembly instruction:

NEG eax

so I did following:

uint32_t a = 0x1234568;
a = reinterpret_cast<uint32_t>(-a);

since reinterpret_cast does what I want, meaning interpreting bytes directly without any kind of casting/conversions.

  • Do I need reinterpret_cast for this purpose?
  • Does this violate strict aliasing?
  • If I do it wrong, what is the best way to implement it?

I'm asking this question because while the code apparently works under gcc, it doesn't work under Visual Studio (cannot convert from uint32_t to uint32_t and unary minus operator applied to unsigned type, result still unsigned). The errors make sense, but I'm not sure how can I do it in a different way except for computing 2's complementary using bit hacks.

rr-
  • 14,303
  • 6
  • 45
  • 67
  • I want it to compute 2's complementary (the same way `NEG` does), i.e. get binary equivalent of the same value stored as negative integer. Note that it isn't the same as `NOT` instruction which just flips all the bits. – rr- Jun 12 '15 at 12:03
  • Specifically I want to avoid doing it manually [like this](http://stackoverflow.com/a/14686025/2016221). – rr- Jun 12 '15 at 12:04
  • 1
    Unless I'm misinterpreting the standard, the `reinterpret_cast` is undefined, not due to a strict aliasing violation, but because the conversion itself is not defined. In this draft http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3225.pdf - 5.2.10 - there's no mention of conversion from a signed integral type to a unsigned integral type. Note especially _"No other conversion can be performed explicitly using reinterpret_cast"_. – davmac Jun 12 '15 at 12:14

2 Answers2

3
  • You don't need reinterpret_cast here, the static_cast is sufficient.
  • Your code doesn't work with pointers so there is no aliasing issue.
  • Conclusion: There is nothing wrong in this approach.

BTW: Your code really compiles to the "neg" instruction, at least on Intel platforms. ;-)


Update:

The C++ language specification says:

The operand of the unary − operator shall have arithmetic or enumeration type and the result is the negation of its operand. Integral promotion is performed on integral or enumeration operands. The negative of an unsigned quantity is computed by subtracting its value from 2n, where n is the number of bits in the promoted operand. The type of the result is the type of the promoted operand.

And since unsigned types are promoted to themselves, the unary minus can be applied to unsigned types and doesn't change them.

So it's correct to write, for example:

uint32_t convert( uint32_t x ) {
    return -x;
}

The static_cast can be used there but it is not needed. The reinterpret_cast cannot be used to convert integers.

dlask
  • 8,776
  • 1
  • 26
  • 30
  • Thanks! Just to be sure: so it's alright to use `static_cast(-static_cast(x));`? (Without these, VS still complains about `-` on unsigned still being unsigned.) – rr- Jun 12 '15 at 12:14
  • _"static_cast is sufficient"_. `static_cast` is always more complex or equivalent to `reinterpret_cast`, so it doesn't make sense. – ElderBug Jun 12 '15 at 12:15
  • @ElderBug It's always better to start with the least aggressive typecast, see http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used . – dlask Jun 12 '15 at 13:12
  • `reinterpret_cast` IS the least aggressive cast. It's the only one that will never do anything. The other casts may or may not add assembly instructions. Though it won't change anything for int and uint, OP wanted to have a single NEG. – ElderBug Jun 12 '15 at 13:22
  • 1
    @ElderBug `reinterpret_cast` cannot be used, because it can't convert an unsigned integral type to its signed equivalent (or vice versa). It's not clear to me why you are claiming that `static_cast` "doesn't make sense". (I do agree though that it is not right to say that `static_cast` is "sufficient". In fact, `static_cast` is _necessary_). – davmac Jun 12 '15 at 13:51
  • @davmac The point here is exactly to NOT convert, because OP _"want it to compute 2's complementary"_. And `reinterpret_cast` can totally be used to cast from unsigned to signed, dunno what you are talking about. Beside, there is no such thing as unsigned to signed conversion in x86 in the first place, so `static_cast` will be treated as a `reinterpret_cast` anyway. – ElderBug Jun 12 '15 at 14:01
  • 1
    @ElderBug _"The point here is exactly to NOT convert"_ - but the negation produces a signed integer, which must be converted back to an unsigned integer. A conversion is necessary unless the negation is avoided. _"And reinterpret_cast can totally be used to cast from unsigned to signed, dunno what you are talking about"_ - no it can't; I'm talking about what the standard says, and what the compiler I tested (g++ 4.6.3) conforms to. Has something changed in a newer version of the standard? – davmac Jun 12 '15 at 14:10
  • @davmac Updated by quoting parts of the C++ language specification. Thank you. – dlask Jun 12 '15 at 14:31
  • @davmac My bad about this point, I forgot that `reinterpret_cast` is so restricted, so `static_cast` will be the only one valid (nothing to do with signed or unsigned). Still, as I already said, there is no such thing as conversion between signed and unsigned, only casts. And even MSVC reminds you that negated unsigned is still unsigned, so there shouldn't be a cast in the first place (see OP's post, `unary minus operator applied to unsigned type, result still unsigned`). – ElderBug Jun 12 '15 at 14:42
  • @ElderBug It appears I was wrong about a negated unsigned int producing a signed int, and this means that you are correct in saying a cast is not needed here. But I have to disagree about one thing: there is certainly conversion between signed and unsigned (and this is what a cast actually does). See [conv.integral] in the standard. – davmac Jun 12 '15 at 14:45
  • @davmac Actually, I agree with that. Conversion between signed and unsigned is definitely defined in the standard. What I had in mind was more about the 2's complement and x86 NEG instruction, where conversion between signed and unsigned are useless (and non-existant). But since this is also what makes the static_cast a no-op, it doesn't matter. – ElderBug Jun 12 '15 at 14:56
0

I would use a = 0 - a;. Or you can have a = -a; however it may give compilation warning. Warning not an error, however it should be avoided.

Also you can try inline assembly.

mov eax, a
neg eax
mov a, eax
ST3
  • 8,826
  • 3
  • 68
  • 92