Какой эффективный или синтаксически простой способ получить и установить часть высокого порядка целого?
С# получить и установить слово высокого порядка целого числа
Ответ 1
Это то же самое, что и в C/С++:
// get the high order 16 bits
int high = 0x12345678 >> 16; // high = 0x1234
// set the high order 16 bits
high = (high & 0x0000FFFF) + (0x5678 << 16); // high = 0x56781234
EDIT: Потому что у меня хорошее настроение, вот и все. Просто помните, неизменные типы неизменяемы! Функции 'set' должны быть привязаны к чему-то.
public static class ExtensionMethods
{
public int LowWord(this int number)
{ return number & 0x0000FFFF; }
public int LowWord(this int number, int newValue)
{ return (number & 0xFFFF0000) + (newValue & 0x0000FFFF); }
public int HighWord(this int number)
{ return number & 0xFFFF0000; }
public int HighWord(this int number, int newValue)
{ return (number & 0x0000FFFF) + (newValue << 16); }
}
РЕДАКТИРОВАТЬ 2: Во-вторых, если вам действительно нужно это делать и вы не хотите синтаксиса повсюду, используйте решение Майкла. +1 ему для показа мне что-то новое.
Ответ 2
uint debugValue = 0xDEADBEEF;
// get
var toExtractHigh = debugValue >> 16;
Console.WriteLine("{0:X}", toExtractHigh);
// set
uint toSetHigh = 0xABAD;
debugValue = debugValue & 0x0000FFFF | toSetHigh << 16;
// this would work too:
// debugValue = debugValue & 0xFFFF | toSetHigh << 16;
Console.WriteLine("{0:X}", debugValue);
Выход:
DEAD
ABADBEEF
С# имеет отличную поддержку переменных, разделяющих одно и то же место в памяти, и структурирование битов.
источник: http://msdn.microsoft.com/en-us/library/acxa5b99(VS.80).aspx
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit)]
struct TestUnion
{
[FieldOffset(0)]
public uint Number;
[FieldOffset(0)]
public ushort Low;
[FieldOffset(2)]
public ushort High;
}
class MainClass
{
public static void Main(string[] args)
{
var x = new TestUnion { Number = 0xABADF00D };
Console.WriteLine("{0:X} {1:X} {2:X}", x.Number, x.High, x.Low);
x.Low = 0xFACE;
Console.WriteLine("{0:X} {1:X} {2:X}", x.Number, x.High, x.Low);
x.High = 0xDEAD;
Console.WriteLine("{0:X} {1:X} {2:X}", x.Number, x.High, x.Low);
}
}
Выход:
ABADF00D ABAD F00D
ABADFACE ABAD FACE
DEADFACE DEAD FACE
ПРИМЕЧАНИЕ. Поскольку в С# нет функции макроса, как в C, вы можете использовать объединенный подход для ускорения процесса. Это более производительно, чем передача переменной в методы/методы расширения
Или, если вы хотите код C в С#, используйте unsafe
unsafe
{
uint value = 0xCAFEFEED;
// x86 is using low-endian.
// So low order array number gets the low order of the value
// And high order array number gets the high order of the value
Console.WriteLine(
"Get low order of {0:X}: {1:X}",
value, ((ushort *) &value)[0]);
Console.WriteLine(
"Get high order of {0:X}: {1:X}",
value, ((ushort*) &value)[1]);
((ushort*) &value)[1] = 0xABAD;
Console.WriteLine("Set high order to ABAD: {0:X}", value);
((ushort*) &value)[0] = 0xFACE;
Console.WriteLine("Set low order to FACE: {0:X}", value);
}
Выход:
Get low order of CAFEFEED: FEED
Get high order of CAFEFEED: CAFE
Set high order to ABAD: ABADFEED
Set low order to FACE: ABADFACE
Еще один unsafe
подход:
unsafe
{
uint value = 0xCAFEFEED;
Console.WriteLine(
"Get low order of {0:X}: {1:X}",
value, ((TestUnion*) &value)->Low);
Console.WriteLine(
"Get high order of {0:X}: {1:X}",
value, ((TestUnion*) &value)->High);
((TestUnion*) &value)->High = 0xABAD;
Console.WriteLine("Set high order to ABAD: {0:X}", value);
((TestUnion*) &value)->Low = 0xFACE;
Console.WriteLine("Set low order to FACE: {0:X}", value);
}
Выход:
Get low order of CAFEFEED: FEED
Get high order of CAFEFEED: CAFE
Set high order to ABAD: ABADFEED
Set low order to FACE: ABADFACE
Ответ 3
Думаю, вам не нужны вычисления, когда вы хотите использовать Hiword/Hibyte или LoWord/Lobyte, если System.Int32 начинается с адреса 100 (поэтому он занимает адрес от 100 до 103), вы хотите как LoWord два байта, начиная с адресов 100 и 101, а Hiword - это адреса 102 и 103.
Это может быть достигнуто с помощью класса BitConverter. Этот класс ничего не делает с битами, он использует только адреса для возврата запрошенного значения.
Поскольку размер таких типов, как int/long, различен для каждой платформы, а WORD и DWORD немного запутывают, я использую типы System.Int16/Int32/Int64. У каждого никогда не будет никаких проблем, угадывающих количество бит в System.Int32.
С помощью BitConverter вы можете преобразовать любое целое число в массив байтов, начиная с этого местоположения, и преобразовать массив байтов соответствующей длины в соответствующее целое число. Никаких расчетов не требуется, и никакие биты не будут меняться,
Предположим, что у вас есть System.Int32 X (который является DWORD в старых терминах)
LOWORD: System.Int16 y = BitConverter.ToInt16(BitConverter.GetBytes(x), 0);
HIWORD: System.Int16 y = BitConverter.ToInt16(BitConverter.GetBytes(x), 2);
Хорошо, что это работает со всеми длинами, вам не нужно комбинировать функции, такие как LOBYTE и HIORD, чтобы получить третий байт:
HIByte(Hiword(x)) will be like: BitConverter.GetBytes(x)[3]
Ответ 4
Другая альтернатива
public class Macro
{
public static short MAKEWORD(byte a, byte b)
{
return ((short)(((byte)(a & 0xff)) | ((short)((byte)(b & 0xff))) << 8));
}
public static byte LOBYTE(short a)
{
return ((byte)(a & 0xff));
}
public static byte HIBYTE(short a)
{
return ((byte)(a >> 8));
}
public static int MAKELONG(short a, short b)
{
return (((int)(a & 0xffff)) | (((int)(b & 0xffff)) << 16));
}
public static short HIWORD(int a)
{
return ((short)(a >> 16));
}
public static short LOWORD(int a)
{
return ((short)(a & 0xffff));
}
}
Ответ 5
Я использую эти две функции...
public static int GetHighint(long intValue)
{
return Convert.ToInt32(intValue >> 32);
}
public static int GetLowint(long intValue)
{
long tmp = intValue << 32;
return Convert.ToInt32(tmp >> 32);
}