С# - создание одного Int64 из двух Int32

Есть ли функция в С#, которая принимает два 32-битных целых числа (int) и возвращает один 64-битный (длинный)?

Похоже, что должен быть простой способ сделать это, но я не смог найти решение.

Ответ 1

Попробуйте выполнить

public long MakeLong(int left, int right) {
  //implicit conversion of left to a long
  long res = left;

  //shift the bits creating an empty space on the right
  // ex: 0x0000CFFF becomes 0xCFFF0000
  res = (res << 32);

  //combine the bits on the right with the previous value
  // ex: 0xCFFF0000 | 0x0000ABCD becomes 0xCFFFABCD
  res = res | (long)(uint)right; //uint first to prevent loss of signed bit

  //return the combined result
  return res;
}

Ответ 2

Просто для ясности... Хотя принятый ответ действительно работает правильно. Все представленные в одном вкладыше не дают точных результатов.

Вот один лайнер, который работает:

long correct = (long)left << 32 | (long)(uint)right;

Вот какой код, чтобы вы могли проверить его самостоятельно:

long original = 1979205471486323557L;
int left = (int)(original >> 32);
int right = (int)(original & 0xffffffffL);

long correct = (long)left << 32 | (long)(uint)right;

long incorrect1 = (long)(((long)left << 32) | (long)right);
long incorrect2 = ((Int64)left << 32 | right);
long incorrect3 = (long)(left * uint.MaxValue) + right;
long incorrect4 = (long)(left * 0x100000000) + right;

Console.WriteLine(original == correct);
Console.WriteLine(original == incorrect1);
Console.WriteLine(original == incorrect2);
Console.WriteLine(original == incorrect3);
Console.WriteLine(original == incorrect4);

Ответ 3

Try

(long)(((long)i1 << 32) | (long)i2)

это сдвигает первый int слева на 32 бита (длина int), затем ors во втором int, так что вы заканчиваете с двумя ints, соединенными вместе длинным.

Ответ 4

Это должно сделать трюк

((Int64) a << 32 | b)

Где a и b - Int32. Хотя вы можете проверить, что происходит с самыми высокими битами. Или просто поместите его в блок "unchecked {...}".

Ответ 5

Обязательно будьте осторожны с подобным битом, хотя вы будете иметь проблемы с маленькими машинами endian/big endian (на платформах Mono не всегда мало endian). Кроме того, вам приходится иметь дело с расширением знака. Математически следующее одно и то же, но имеет дело с расширением знака и является агностиком платформы.

return (long)( high * uint.MaxValue ) + low;

При запуске во время выполнения это приведет к тому, что производительность будет похожа на бит. Это одна из приятных вещей о интерпретируемых языках.

Ответ 6

Будьте осторожны с битом знака. Вот быстрое решение ulong, которое также не переносимо с прямым порядком байтов:

    var a = 123;
    var b = -123;

    unsafe
    {
        ulong result = *(uint*)&a;

        result <<= 32;
        result |= *(uint*)&b;
    }

Ответ 7

Существует проблема, когда i2 <0 - будут установлены старшие 32 бита (0xFFFFFFFF, 1xxx... двоичный) - цикл был неверным
Лучше было бы что-то вроде (Int64) (((UInt64) i1 << 32) | (UInt32) i2)

Или просто C++

public static unsafe UInt64 MakeLong(UInt32 low, UInt32 high)
{
    UInt64 retVal;
    UInt32* ptr = (UInt32*)&retVal;
    *ptr++ = low;
    *ptr = high;
    return retVal;
}

UInt64 retVal;
unsafe
{
    UInt32* ptr = (UInt32*)&retVal;
    *ptr++ = low;
    *ptr = high;
}

Но лучшее решение, найденное тогда здесь ;-)
[StructLayout (LayoutKind.Explicit)]
[FieldOffset()]
fooobar.com/info/459733/...
(даже без небезопасных). В любом случае FieldOffset работает для каждого элемента, поэтому вы должны указать положение каждой половины отдельно и помнить, что отрицательные числа # являются нулевыми дополнениями, поэтому ex. низкий <0 и высокий> 0 не будут иметь смысла - например, -1, 0 даст Int64 как 4294967295, вероятно.