Page 1 of 1
Swapping high/low DWORDS in a QWORD [SOLVED]
Posted: Wed Feb 03, 2010 7:16 pm
by AndrewAPrice
I'm trying to swap the high/low DWORDs in a QWORD. I reference the QWORD as an array of two DWORDS and swap them, but after doing so the value of the QWORD is scrambled. Optimisations are disabled (MSVC++ 2008) and I've even tried making varToSwap and *p volatile but the output is no difference.
Code: Select all
unsigned long long varToSwap; // initially in 0x0000 0000 FFFF E000 in my code
unsigned int t;
unsigned int *p = (unsigned int *)&varToSwap;
t = p[0];
p[0] = p[1];
p[1] = t;
// debugger says:
// t = 0xFFFF E000
// p[0] = 0x0000 0000
// p[1] = 0xFFFF E000
// varToSwap = 0x1999 9666 6666 6666 (wrong, wanted 0xFFFF E000 0000 0000)
Is there something very obvious that I have overlooked?
Re: Swapping high/low DWORDS in a QWORD
Posted: Wed Feb 03, 2010 7:41 pm
by pcmattman
Tried disassembling it?
Re: Swapping high/low DWORDS in a QWORD
Posted: Wed Feb 03, 2010 8:21 pm
by midir
It looks right to me, but a union should work too (and maybe would give better code, by not requiring the variable to be moved to a pointer first, if the compiler is smart, and would avoid the risk of memory corruption on some environment where long long is not 2 ints in size).
Re: Swapping high/low DWORDS in a QWORD
Posted: Wed Feb 03, 2010 9:04 pm
by 01000101
That is quite odd. I just created a small "app" that does this with GCC just to make sure the logic was correct and the following code worked as expected:
Code: Select all
#include <stdint.h>
#include <string.h>
#include <stdio.h>
int main( int argc, char **argv )
{
uint64_t i64 = (uint64_t)0xFFEE112200000000LL;
uint32_t tmp;
uint32_t *a32 = (uint32_t *)&i64;
/* Show the "before"... */
printf("i64(before) = 0x%llX\n", i64);
/* Swap! */
tmp = a32[0];
a32[0] = a32[1];
a32[1] = tmp;
/* Show the "after"... */
printf("i64(after) = 0x%llX\n", i64);
}
Compiled with "gcc -m32 -std=c99 -pedantic -Wall swap.c".
Maybe give that a try and see if it's still wrong in MSVC?
Re: Swapping high/low DWORDS in a QWORD
Posted: Wed Feb 03, 2010 9:30 pm
by midir
Actually, this should be sufficient, never mind pointers or unions or all that rubbish:
q = (q << 32) | ((q >> 32) & 0xFFFFFFFF);
Re: Swapping high/low DWORDS in a QWORD
Posted: Wed Feb 03, 2010 10:52 pm
by AndrewAPrice
01000101, the code worked under Cygwin/GCC.
midir wrote:
q = (q << 32) | ((q >> 32) & 0xFFFFFFFF);
->
Code: Select all
'<<' : result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)"
'>>' : shift count negative or too big, undefined behavior
Then the result is also weird. I'm think I need to reinstall Visual Studio since my compiler is being very buggy. I'm getting crashes when I attempt to call 'new' or malloc. If the problem still persists I'll report the bug to MS.
Thanks for your help.
Re: Swapping high/low DWORDS in a QWORD [SOLVED]
Posted: Wed Feb 03, 2010 10:55 pm
by pcmattman
You might want to use "unsigned __int64" rather than "long long" too to explicitly tell the compiler you want a 64-bit type. Just a thought, although long long should really be 64-bit
Re: Swapping high/low DWORDS in a QWORD [SOLVED]
Posted: Wed Feb 03, 2010 11:12 pm
by neon
Tested in MSVC 2008 and the original code worked as expected...
Re: Swapping high/low DWORDS in a QWORD [SOLVED]
Posted: Thu Feb 04, 2010 3:53 am
by Owen
Your code violates C aliasing rules. It may work in some contexts and not in others; it's up to the compiler.
The standard states that two pointers of different types may never reference the same region of memory. For this kind of thing, either use a union or series of shifts.