C # получить и установить старшее слово целого числа - PullRequest
14 голосов
/ 17 сентября 2009

Какой эффективный или синтаксически простой способ получить и установить старшую часть целого числа?

Ответы [ 5 ]

26 голосов
/ 17 сентября 2009
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

C # имеет отличную поддержку для переменных, совместно использующих одно и то же место в памяти, и структурирование битов

источник: 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 # нет функции macro , как в C, вы можете использовать подход union для ускорения процесса. Это более производительно, чем передача переменной в методы / методы расширения

Или, если вы хотите кодировать 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
19 голосов
/ 17 сентября 2009

Это так же, как в C / 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

РЕДАКТИРОВАТЬ: Потому что я в хорошем настроении, вот и все. Просто помните, неизменные типы неизменны! Функции '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 ему за то, что показал мне что-то новое.

4 голосов
/ 22 ноября 2013

Полагаю, вам не нужны вычисления, когда вам нужны 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]
1 голос
/ 25 февраля 2016

Другая альтернатива

    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));
        }
    }
0 голосов
/ 12 июля 2014

Я использую эти 2 функции ...

    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);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...