开发者

Convert a long to two int for the purpose of reconstruction

I need to pass a parameter as two int parameters to a Telerik Report since it cannot accept Long parameters. What is the easie开发者_如何学Gost way to split a long into two ints and reconstruct it without losing data?


Using masking and shifting is your best bet. long is guaranteed to be 64 bit and int 32 bit, according to the documentation, so you can mask off the bits into the two integers and then recombine.

See:

    static int[] long2doubleInt(long a) {
        int a1 = (int)(a & uint.MaxValue);
        int a2 = (int)(a >> 32);
        return new int[] { a1, a2 };
    }

    static long doubleInt2long(int a1, int a2)
    {
        long b = a2;
        b = b << 32;
        b = b | (uint)a1;
        return b;
    }


    static void Main(string[] args)
    {
        long a = 12345678910111213;
        int[] al = long2doubleInt(a);
        long ap = doubleInt2long(al[0],al[1]);
        System.Console.WriteLine(ap);
        System.Console.ReadKey();
    }

Note the use of bitwise operations throughout. This avoids the problems one might get when using addition or other numerical operations that might occur using negative numbers or rounding errors.

Note you can replace int with uint in the above code if you are able to use unsigned integers (this is always preferable in this sort of situation, as it's a lot clearer what's going on with the bits).


Doing bit-manipulation in C# can be awkward at times, particularly when dealing with signed values. You need to be using unsigned values whenever you plan on doing bit-manipulation. Unfortunately it's not going to yield the nicest looking code.

const long LOW_MASK = ((1L << 32) - 1);
long value = unchecked((long)0xDEADBEEFFEEDDEAD);
int valueHigh = (int)(value >> 32);
int valueLow  = (int)(value & LOW_MASK);
long reconstructed = unchecked((long)(((ulong)valueHigh << 32) | (uint)valueLow));

If you want a nicer way to do this, get the raw bytes for the long and get the corresponding integers from the bytes. The conversion to/from representations doesn't change very much.

long value = unchecked((long)0xDEADBEEFFEEDDEAD);
byte[] valueBytes = BitConverter.GetBytes(value);
int valueHigh = BitConverter.ToInt32(valueBytes, BitConverter.IsLittleEndian ? 4 : 0);
int valueLow  = BitConverter.ToInt32(valueBytes, BitConverter.IsLittleEndian ? 0 : 4);
byte[] reconstructedBytes = BitConverter.IsLittleEndian
    ? BitConverter.GetBytes(valueLow).Concat(BitConverter.GetBytes(valueHigh)).ToArray()
    : BitConverter.GetBytes(valueHigh).Concat(BitConverter.GetBytes(valueLow)).ToArray();
long reconstructed = BitConverter.ToInt64(reconstructedBytes, 0);


For unigned the following will work:

ulong value = ulong.MaxValue - 12;
uint low = (uint)(value & (ulong)uint.MaxValue);
uint high = (uint)(value >> 32);

ulong value2 = ((ulong)high << 32) | low;


        long x = long.MaxValue;
        int lo = (int)(x & 0xffffffff);
        int hi = (int)((x - ((long)lo & 0xffffffff)) >> 32);
        long y = ((long)hi << 32) | ((long)lo & 0xffffffff);

        Console.WriteLine(System.Convert.ToString(x, 16));
        Console.WriteLine(System.Convert.ToString(lo, 16));
        Console.WriteLine(System.Convert.ToString(hi, 16));
        Console.WriteLine(System.Convert.ToString(y, 16));


Converting it to and from a string would be much simpler than converting it two and from a pair of ints. Is this an option?

string myStringValue = myLongValue.ToString();

myLongValue = long.Parse(myStringValue);


Instead of mucking with bit operations, just use a faux union. This also would work for different combinations of data types, not just long & 2 ints. More importantly, that avoids the need to be concerned about signs, endianness or other low-level details when you really only care about reading & writing bits in a consistent manner.

using System;
using System.Runtime.InteropServices;

public class Program
{
    [StructLayout(LayoutKind.Explicit)]
    private struct Mapper
    {
        [FieldOffset(0)]
        public long Aggregated;
        [FieldOffset(0)]
        public int One;
        [FieldOffset(sizeof(int))]
        public int Two;
    }
    
    public static void Main()
    {
        var layout = new Mapper{ Aggregated = 0x00000000200000001 };
        var one = layout.One;
        var two = layout.Two;
        Console.WriteLine("One: {0}, Two: {1}", one, two);
        
        var secondLayout = new Mapper { One = one, Two = two };
        var aggregated = secondLayout.Aggregated;
        Console.WriteLine("Aggregated: {0}", aggregated.ToString("X"));
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜