Swapping high/low DWORDS in a QWORD [SOLVED]

Programming, for all ages and all languages.
Post Reply
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Swapping high/low DWORDS in a QWORD [SOLVED]

Post 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?
Last edited by AndrewAPrice on Wed Feb 03, 2010 10:53 pm, edited 1 time in total.
My OS is Perception.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Swapping high/low DWORDS in a QWORD

Post by pcmattman »

Tried disassembling it?
midir
Member
Member
Posts: 46
Joined: Fri Jun 13, 2008 4:09 pm

Re: Swapping high/low DWORDS in a QWORD

Post 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).
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Re: Swapping high/low DWORDS in a QWORD

Post 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?
midir
Member
Member
Posts: 46
Joined: Fri Jun 13, 2008 4:09 pm

Re: Swapping high/low DWORDS in a QWORD

Post by midir »

Actually, this should be sufficient, never mind pointers or unions or all that rubbish:
q = (q << 32) | ((q >> 32) & 0xFFFFFFFF); :roll:
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Re: Swapping high/low DWORDS in a QWORD

Post by AndrewAPrice »

01000101, the code worked under Cygwin/GCC.
midir wrote: q = (q << 32) | ((q >> 32) & 0xFFFFFFFF); :roll:
->

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.
My OS is Perception.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Swapping high/low DWORDS in a QWORD [SOLVED]

Post 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
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Swapping high/low DWORDS in a QWORD [SOLVED]

Post by neon »

Tested in MSVC 2008 and the original code worked as expected...
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: Swapping high/low DWORDS in a QWORD [SOLVED]

Post 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.
Post Reply