问题
I'm converting some 32-bit compatible code into 64-bit - and I've hit a snag. I'm compiling a VS2008 x64 project, and I receive this warning:
warning C4334: '<<' : result of 32-bit shift implicitly converted to 64 bits
(was 64-bit shift intended?)
Here's the original line of code:
if ((j & (1 << k)) != 0) {
And here's what it looks like if I follow Microsoft's advice:
if ((j & (1i64 << k)) != 0) {
Is this safe to do, when the code will be compiled on both 32-bit and 64-bit systems? If so, please explain why I must add "i64" to the end, and why this will not affect a 32-bit compilation. Otherwise, a work-around would be much appreciated.
Beyond this, I have what looks like an even trickier bit of code.
if (id[j] != id[j ^ (1u << k)]) {
I understand that the "u" means that the digit is unsigned, but what's the point in specifying that on a value that doesn't exceed the signed maximum value... I'm guessing this has something to do with the bit shift?
回答1:
1
has type int
according to C++ Standard. On 64-bit Microsoft compiler int
has sizeof = 4 bytes, it means that int
is 32-bit variable. 1i64
has type __int64
.
When you use shift operator the type of the result is the same as the type of the left operand. It means that shifting 1
you'll get 32-bit result. Microsoft compiler assumes that it could be not what you are expecting (on 64-bit platform) and gives you warning message.
When you use 1i64
result will be 64-bit on both platforms. j
and 0
will be implicitly casted to 64-bit. So the whole expression will be calculated in 64-bit variables and result will be bool
.
So using 1i64
is safe on both (32/64) platforms.
回答2:
The i64
suffix is Microsoft-specific. To be more portable (if you're worried about that), you might use the INT64_C()
macro from stdint.h
:
#include <stdint.h>
// ...
if ((j & (INT64_C( 1) << k)) != 0) { ... }
Unfortunately, MS doesn't have stdint.h
as part of their C library (most other compilers seem to have it), but fortunately you can get one from several sources:
- http://snipplr.com/view/18199/stdinth/
- http://msinttypes.googlecode.com/svn/trunk/stdint.h
- http://www.azillionmonkeys.com/qed/pstdint.h
Now you'll have a 64-bit constant that'll work with a wide variety of compilers.
As far as why you might want or need the 64-bit value, it depends on the types of the various parts of the expression. It would be helpful to know the types of id
, j
, and k
to be able to answer whether you need the the 'u
' suffix on the constant or not, and what effect it might have.
回答3:
1i64 I believe should be a signed, 64-bit integer. I can't proclaim any expertise in Microsoft's implementation, but in GCC, the solution for supporting 64-bit integers on 32-bit CPUs was to make long longs double-words using structs and various black magic macros. Therefore, i64 should be compatible.
As to the last bit of voodoo -- the only point in specifying 1u it is because it's possible that if k is large enough, the result of the shift would meet / exceed 32-bits of storage, in which case the outcome will be different if the LH operand is treated as a signed or an unsigned integer.
回答4:
Since that code is 'and'ing the 64-bit variable j
with the (32-bit) result of a bit-shift, the result will be 'expanded' to 64 bit by the compiler.
You probably want to be in control of how the second operand to the 'and' is calculated, so the compiler suggests you use the full 64 bits by making the first operand an __int64
. This is safe in 32 bit, but you should actually look at the type of j
to decide on the operator being 32 or 64 bit.
That's especially important in the second bit, where the result is used as an index.
来源:https://stackoverflow.com/questions/1264059/in-c-what-is-the-difference-between-1-and-1i64