Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# get and set the high order word of an integer

Tags:

c#

What's an efficient or syntactically simple way to get and set the high order part of an integer?

like image 337
James Cadd Avatar asked Sep 17 '09 00:09

James Cadd


2 Answers

There are multiple ways of achieving that, here are some of them.


Using the Bitwise and/or Shift operators

Applying a right shift in an integer will move the bits to the right, putting zeros to the left.
In the case below, it will shift the size of a short (Int16, as 16 bits).

Applying a logical AND (&) operation in an integer like 0x0000FFFF will basically 'cut' the value (where it's F) and ignore the rest (where it's 0).
Remember that in the end it's just a 0b_1 AND 0b_1 = 0b_1 operation, so any 0b_0 AND 0b_1 will result in 0b_0.

Applying a logical OR (|) operation will basically merge the two numbers in this case, like 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}");

Output:

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

Using FieldOffsetAttribute in a struct

C# has excellent support for variables sharing the same memory location, and bits structuring.

Since C# has no macro functions like in C, you can use the union approach to speed things up. It's more performant than passing the variable to methods or extension methods.

You can do that by simply creating a struct with explicit layout and setting the offset of the fields:

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

Output:

ABADF00D ABAD F00D
ABADFACE ABAD FACE
DEADFACE DEAD FACE

Mind that with Visual Studio 2029 (16.7), you still may get zeros in x.High and x.Low when adding the variable x inside the Watch or by hovering your cursor on top of the variables x.High and x.Low directly.

Visual Studio Bug


Using unsafe and pointer element access operator []

To a more akin to C programming, but in C#, use 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);
}

Output:

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 ->

Another unsafe approach, but this time accessing a member from the WordUnion struct declared in a previous example:

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

Output:

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 the BitConverter class

It simply gets 16 bits (2 bytes, a short/Int16) from the specified number. The offset can be controlled by the second parameter.

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

Output:

Low: 0xCAFE
High: 0xFEED
like image 82
Michael Buen Avatar answered Oct 15 '22 12:10

Michael Buen


It's the same as 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

EDIT: Because I'm in a good mood, here you go. Just remember, immutable types are immutable! The 'set' functions need to be assigned to something.

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

EDIT 2: On second thoughts, if you really need to do this and don't want the syntax everywhere, use Michael's solution. +1 to him for showing me something new.

like image 23
Matthew Scharley Avatar answered Oct 15 '22 10:10

Matthew Scharley