C# erhält und setzt das höherwertige Wort einer Ganzzahl

C# erhält und setzt das höherwertige Wort einer Ganzzahl

Es gibt mehrere Möglichkeiten, dies zu erreichen, hier sind einige davon.

Verwendung der Bitwise- und/oder Shift-Operatoren

Wenn Sie eine Ganzzahl nach rechts verschieben, werden die Bits nach rechts verschoben und Nullen nach links gesetzt.
Im folgenden Fall wird die Größe eines Short verschoben (Int16, als 16 Bit).

Anwenden einer logischen UND-Operation (&) in einer Ganzzahl wie 0x0000FFFF wird den Wert im Grunde "kürzen" (wobei es F ist ) und ignoriere den Rest (wo es 0 ist ).
Denken Sie daran, dass es am Ende nur eine 0b_1 AND 0b_1 = 0b_1 ist Operation, also beliebig 0b_0 AND 0b_1 ergibt 0b_0 .

Durch das Anwenden einer logischen ODER-Operation (|) werden die beiden Zahlen in diesem Fall im Grunde zusammengeführt, z. B. 0b_10 | 0b_01 = 0b_11 .

Code:

uint number = 0xDEADBEEF;

//Get the higher order value.
var high = number >> 16;
Console.WriteLine($"High: {high:X}");

//Get the lower order value.
var low = number & 0xFFFF; //Or use 0x0000FFFF
Console.WriteLine($"Low: {low:X}");

//Set a high order value (you can also use 0xFFFF instead of 0x0000FFFF).
uint newHigh = 0xFADE;
number = number & 0x0000FFFF | newHigh << 16;
Console.WriteLine($"New high: {number:X}");

//Set a low order value.
uint newLow = 0xC0DE;
number = number & 0xFFFF0000 | newLow & 0x0000FFFF;
Console.WriteLine($"New low: {number:X}");

Ausgabe:

High: DEAD
Low: BEEF
New high: FADEBEEF
New low: FADEC0DE

FieldOffsetAttribute in einer Struktur verwenden

C# bietet eine hervorragende Unterstützung für Variablen, die sich denselben Speicherort teilen, und für die Strukturierung von Bits.

Da C# kein Makro hat Funktionen wie in C, können Sie die Union verwenden Ansatz, um die Dinge zu beschleunigen. Es ist performanter, als die Variable an Methoden oder Erweiterungsmethoden zu übergeben.

Sie können dies tun, indem Sie einfach eine Struktur mit explizitem Layout erstellen und den Offset der Felder festlegen:

Code:

using System;
using System.Runtime.InteropServices;
   
[StructLayout(LayoutKind.Explicit)]
struct WordUnion
{
    [FieldOffset(0)]
    public uint Number;

    [FieldOffset(0)]
    public ushort Low;

    [FieldOffset(2)]
    public ushort High;
}
    
public class MainClass
{
    public static void Main(string[] args)
    {        
        var x = new WordUnion { 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);
    }
}

Ausgabe:

ABADF00D ABAD F00D
ABADFACE ABAD FACE
DEADFACE DEAD FACE

Verwenden des unsicheren Zugriffsoperators und Zeigerelementzugriffsoperators []

Um einer C-Programmierung ähnlicher zu sein, aber in C#, verwenden Sie unsafe :

Code:

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);
}

Ausgabe:

Get low order of CAFEFEED: FEED
Get high order of CAFEFEED: CAFE
Set high order to ABAD: ABADFEED
Set low order to FACE: ABADFACE

Using unsafe and pointer member access operator ->

Noch ein unsafe Ansatz, aber dieses Mal greifen Sie auf ein Mitglied von WordUnion zu struct in einem vorherigen Beispiel deklariert:

Code:

unsafe
{
    uint value = 0xCAFEFEED;

    Console.WriteLine("Get low order of {0:X}: {1:X}", 
        value, ((WordUnion*) &value)->Low);

    Console.WriteLine("Get high order of {0:X}: {1:X}", 
        value, ((WordUnion*) &value)->High);


    ((WordUnion*) &value)->High = 0xABAD;
    Console.WriteLine($"Set high order to ABAD: {value:X}");

    ((WordUnion*) &value)->Low = 0xFACE;
    Console.WriteLine($"Set low order to FACE: {value:X}");
}

Ausgabe:

Get low order of CAFEFEED: FEED
Get high order of CAFEFEED: CAFE
Set high order to ABAD: ABADFEED
Set low order to FACE: ABADFACE

Verwendung der BitConverter-Klasse

Es werden einfach 16 Bits (2 Bytes, ein short /Int16 ) von der angegebenen Nummer. Der Offset kann über den zweiten Parameter gesteuert werden.

Code:

uint value = 0xCAFEFEED;

var low = BitConverter.ToInt16(BitConverter.GetBytes(value), 0);
var high = BitConverter.ToInt16(BitConverter.GetBytes(value), 2);

Console.WriteLine($"Low: {low:X}");
Console.WriteLine($"High: {high:X}");

Ausgabe:

Low: 0xCAFE
High: 0xFEED

Es ist dasselbe wie in 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

BEARBEITEN: Weil ich gute Laune habe, bitte schön. Denken Sie daran, unveränderliche Typen sind unveränderlich! Die 'Set'-Funktionen müssen etwas zugewiesen werden.

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); }
}

BEARBEITEN 2: Wenn Sie dies wirklich tun müssen und die Syntax nicht überall haben möchten, verwenden Sie Michaels Lösung. +1 für ihn, weil er mir etwas Neues gezeigt hat.


Ich denke, Sie wollen keine Berechnungen, wenn Sie das Hiword / Hibyte oder das LoWord / Lobyte wollen. Wenn ein System.Int32 bei Adresse 100 beginnt (also die Adresse 100 bis 103 belegt), möchten Sie als LoWord die beiden Bytes beginnen bei Adresse 100 und 101 und Hiword ist Adresse 102 und 103.

Dies kann mit der Klasse BitConverter erreicht werden. Diese Klasse macht nichts mit den Bits, sie verwendet nur die Adressen, um den angeforderten Wert zurückzugeben.

Da die Größe von Typen wie int / long pro Plattform unterschiedlich ist und WORD und DWORD etwas verwirrend sind, verwende ich die Systemtypen System.Int16/Int32/Int64. Niemand wird jemals Probleme haben, die Anzahl der Bits in einer System.Int32 zu erraten.

Mit BitConverter können Sie jede Ganzzahl in das Array von Bytes konvertieren, die an dieser Stelle beginnen, und ein Array von Bytes der richtigen Länge in die entsprechende Ganzzahl konvertieren. Keine Berechnungen erforderlich und keine Bits ändern sich,

Angenommen, Sie haben ein System.Int32 X (was in alten Begriffen ein DWORD ist)

LOWORD: System.Int16 y = BitConverter.ToInt16(BitConverter.GetBytes(x), 0);
HIWORD: System.Int16 y = BitConverter.ToInt16(BitConverter.GetBytes(x), 2);

Das Schöne ist, dass dies mit allen Längen funktioniert, Sie müssen Funktionen wie LOBYTE und HIWORD nicht kombinieren, um das dritte Byte zu erhalten:

HIByte(Hiword(x)) will be like: BitConverter.GetBytes(x)[3]