Different results using the crc32 function between C# and php - c#
I have been preparing a big list of words using crc32 for hashing each word, I do this process on C# but there is a process on php, my surprise comes when I see that the crc32 function used in C# produces different hash than the standard crc32 function on PHP.
The function on C# gives an unsigned int and php gives signed int but doing printf("%u\n", $crc_value) you can obtaind the usigned int, however this neither match the C# value.
(I put on the bottom the C# code)
Is there a way to ajust the php function for give me the same results?
I put here hashes produces in each language:
php:
$value = crc32("emisiones")
//signed int => 1277409361
//unsigned int => 1277409361
c#:
Crc32.CRC32String("emisiones");
// unsigned int => 3523227667
Crc32.CRC32Bytes(System.Text.Encoding.ASCII.GetBytes("emisiones"));
// bytes => 101,109,105,115,105,111,110,101,115
// unsigned int => 3525485962
crc32 implementation of c#:
using System;
using System.IO;
namespace Foo
{
/// <summary>
/// A utility class to compute CRC32.
/// </summary>
public class Crc32
{
private uint _crc32 = 0;
static private uint[] crc_32_tab = // CRC polynomial 0xedb88320
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
static private uint UPDC32(byte octet, uint crc)
{
return (crc_32_tab[((crc) ^ ((byte)octet)) & 0xff] ^ ((crc) >> 8));
}
internal uint CheckSum
{
get
{
return _crc32;
}
set
{
_crc32 = value;
}
}
internal uint AddToCRC32(int c)
{
return AddToCRC32((ushort)c);
}
internal uint AddToCRC32(ushort c)
{
byte lowByte, hiByte;
lowByte = (byte)(c & 0x00ff);
hiByte = (byte)(c >> 8);
_crc32 = UPDC32(hiByte, _crc32);
_crc32 = UPDC32(lowByte, _crc32);
return ~_crc32;
}
/// <summary>
/// Compute a checksum for a given string.
/// </summary>
/// <param name="text">The string to compute the checksum for.</param>
/// <returns>The computed checksum.</returns>
static public uint CRC32String(string text)
{
uint oldcrc32;
oldcrc32 = 0xFFFFFFFF;
int len = text.Length;
ushort uCharVal;
byte lowByte, hiByte;
for (int i = 0; len > 0; i++)
{
--len;
uCharVal = text[len];
unchecked
{
lowByte = (byte)(uCharVal & 0x00ff);
hiByte = (byte)(uCharVal >> 8);
}
oldcrc32 = UPDC32(hiByte, oldcrc32);
oldcrc32 = UPDC32(lowByte, oldcrc32);
}
return ~oldcrc32;
}
/// <summary>
/// Compute a checksum for a given array of bytes.
/// </summary>
/// <param name="bytes">The array of bytes to compute the checksum for.</param>
/// <returns>The computed checksum.</returns>
static public uint CRC32Bytes(byte[] bytes)
{
uint oldcrc32;
oldcrc32 = 0xFFFFFFFF;
int len = bytes.Length;
for (int i = 0; len > 0; i++)
{
--len;
oldcrc32 = UPDC32(bytes[len], oldcrc32);
}
return ~oldcrc32;
}
}
}
CRC32String() is running two bytes per character through. If you are expecting one byte per character, as the PHP code would, then you should use CRC32Bytes().
Having done that, you need to fix both of those routines. They are computing the CRC on the reverse of the string. (Who wrote those routines?) If you run CRC32Bytes() on "senoisime", then you will get 1277409361. And if you run php's crc32() on "senoisime", you will get 3525485962.
CRC32String() and CRC32Bytes() use text[len] and bytes[len] when they should be using text[i] and bytes[i]. i counts forward, but len counts backwards. This is clearly just someone's brain fart, since you wouldn't even need the variable i if you actually intended to compute the CRC on the reverse of the string.
Also it's a rather odd way to write the code in the first place. They should have just used the most common C-ish idiom instead: for (i = 0; i < len; i++).
Related
How to increase volume/amplitude on raw audio bytes
I'm working with phone raw phone sounds and recordings and I want to normalize them to a certain volume level in a .Net C# project. The sound is a collection of raw audio bytes (mono unheadered 16-bit signed PCM audio 16000Hz). The audio is split into blocks of 3200 bytes == 100ms. Any suggestions how to increase the volume/amplitude so the sounds is louder? I haven't got a clue if I need to add a constant or multiply values, or if I need to do it to every 1,2,3.... bytes? And maybe there is already a open source solution for this?
To answer my own question (for others). The solution is to multiply every sample (when 16bit PCM that are 2 bytes) with a constant value. Do avoid overflow\to much increase you can calculate the highest constant value you can use by looking for the highest sample value and calculate the multiply factor to get it to highest sample value possible, in 16bit PCM case thats 32676 or something. Here is litle example: public byte[] IncreaseDecibel(byte[] audioBuffer, float multiplier) { // Max range -32768 and 32767 var highestValue = GetHighestAbsoluteSample(audioBuffer); var highestPosibleMultiplier = (float)Int16.MaxValue/highestValue; // Int16.MaxValue = 32767 if (multiplier > highestPosibleMultiplier) { multiplier = highestPosibleMultiplier; } for (var i = 0; i < audioBuffer.Length; i = i + 2) { Int16 sample = BitConverter.ToInt16(audioBuffer, i); sample *= (Int16)(sample * multiplier); byte[] sampleBytes = GetLittleEndianBytesFromShort(sample); audioBuffer[i] = sampleBytes[sampleBytes.Length-2]; audioBuffer[i+1] = sampleBytes[sampleBytes.Length-1]; } return audioBuffer; } // ADDED GetHighestAbsoluteSample, hopefully its still correct because code has changed over time /// <summary> /// Peak sample value /// </summary> /// <param name="audioBuffer">audio</param> /// <returns>0 - 32768</returns> public static short GetHighestAbsoluteSample(byte[] audioBuffer) { Int16 highestAbsoluteValue = 0; for (var i = 0; i < (audioBuffer.Length-1); i = i + 2) { Int16 sample = ByteConverter.GetShortFromLittleEndianBytes(audioBuffer, i); // prevent Math.Abs overflow exception if (sample == Int16.MinValue) { sample += 1; } var absoluteValue = Math.Abs(sample); if (absoluteValue > highestAbsoluteValue) { highestAbsoluteValue = absoluteValue; } } return (highestAbsoluteValue > LowestPossibleAmplitude) ? highestAbsoluteValue : LowestPossibleAmplitude; }
Is this the correct way to truncate a hash in C#?
I have a requirement to hash input strings and produce 14 digit decimal numbers as output. The math I am using tells me I can have, at maximum, a 46 bit unsigned integer. I am aware that a 46 bit uint means less collision resistance for any potential hash function. However, the number of hashes I am creating keeps the collision probability in an acceptable range. I would be most grateful if the community could help me verify that my method for truncating a hash to 46 bits is solid. I have a gut feeling that there are optimizations and/or easier ways to do this. My function is as follows (where bitLength is 46 when this function is called): public static UInt64 GetTruncatedMd5Hash(string input, int bitLength) { var md5Hash = MD5.Create(); byte[] fullHashBytes = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input)); var fullHashBits = new BitArray(fullHashBytes); // BitArray stores LSB of each byte in lowest indexes, so reversing... ReverseBitArray(fullHashBits); // truncate by copying only number of bits specified by bitLength param var truncatedHashBits = new BitArray(bitLength); for (int i = 0; i < bitLength - 1; i++) { truncatedHashBits[i] = fullHashBits[i]; } byte[] truncatedHashBytes = new byte[8]; truncatedHashBits.CopyTo(truncatedHashBytes, 0); return BitConverter.ToUInt64(truncatedHashBytes, 0); } Thanks for taking a look at this question. I appreciate any feedback!
With the help of the comments above, I crafted the following solution: public static UInt64 GetTruncatedMd5Hash(string input, int bitLength) { if (string.IsNullOrWhiteSpace(input)) throw new ArgumentException("input must not be null or whitespace"); if(bitLength > 64) throw new ArgumentException("bitLength must be <= 64"); var md5Hash = MD5.Create(); byte[] fullHashBytes = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input)); if(bitLength == 64) return BitConverter.ToUInt64(fullHashBytes, 0); var bitMask = (1UL << bitLength) - 1UL; return BitConverter.ToUInt64(fullHashBytes, 0) & bitMask; } It's much tighter (and faster) than what I was trying to do before.
How to set each bit in a byte array
How do I set each bit in the following byte array which has 21 bytes or 168 bits to either zero or one? byte[] logonHours Thank you very much
Well, to clear every bit to zero you can just use Array.Clear: Array.Clear(logonHours, 0, logonHours.Length); Setting each bit is slightly harder: for (int i = 0; i < logonHours.Length; i++) { logonHours[i] = 0xff; } If you find yourself filling an array often, you could write an extension method: public static void FillArray<T>(this T[] array, T value) { // TODO: Validation for (int i = 0; i < array.Length; i++) { array[i] = value; } }
BitArray.SetAll: System.Collections.BitArray a = new System.Collections.BitArray(logonHours); a.SetAll(true); Note that this copies the data from the byte array. It's not just a wrapper around it.
This may be more than you need, but ... Usually when dealing with individual bits in any data type, I define a const for each bit position, then use the binary operators |, &, and ^. i.e. const byte bit1 = 1; const byte bit2 = 2; const byte bit3 = 4; const byte bit4 = 8; . . const byte bit8 = 128; Then you can turn whatever bits you want on and off using the bit operations. byte byTest = 0; byTest = byTest | bit4; would turn bit 4 on but leave the rest untouched. You would use the & and ^ to turn them off or do more complex exercises. Obviously, since you only want to turn all bits up or down then you can just set the byte to 0 or 255. That would turn them all off or on.
Variable length encoding of an integer
Whats the best way of doing variable length encoding of an unsigned integer value in C# ? "The actual intent is to append a variable length encoded integer (bytes) to a file header." For ex: "Content-Length" - Http Header Can this be achieved with some changes in the logic below. I have written some code which does that ....
A method I have used, which makes smaller values use fewer bytes, is to encode 7 bits of data + 1 bit of overhead pr. byte. The encoding works only for positive values starting with zero, but can be modified if necessary to handle negative values as well. The way the encoding works is like this: Grab the lowest 7 bits of your value and store them in a byte, this is what you're going to output Shift the value 7 bits to the right, getting rid of those 7 bits you just grabbed If the value is non-zero (ie. after you shifted away 7 bits from it), set the high bit of the byte you're going to output before you output it Output the byte If the value is non-zero (ie. same check that resulted in setting the high bit), go back and repeat the steps from the start To decode: Start at bit-position 0 Read one byte from the file Store whether the high bit is set, and mask it away OR in the rest of the byte into your final value, at the bit-position you're at If the high bit was set, increase the bit-position by 7, and repeat the steps, skipping the first one (don't reset the bit-position) 39 32 31 24 23 16 15 8 7 0 value: |DDDDDDDD|CCCCCCCC|BBBBBBBB|AAAAAAAA| encoded: |0000DDDD|xDDDDCCC|xCCCCCBB|xBBBBBBA|xAAAAAAA| (note, stored in reverse order) As you can see, the encoded value might occupy one additional byte that is just half-way used, due to the overhead of the control bits. If you expand this to a 64-bit value, the additional byte will be completely used, so there will still only be one byte of extra overhead. Note: Since the encoding stores values one byte at a time, always in the same order, big- or little-endian systems will not change the layout of this. The least significant byte is always stored first, etc. Ranges and their encoded size: 0 - 127 : 1 byte 128 - 16.383 : 2 bytes 16.384 - 2.097.151 : 3 bytes 2.097.152 - 268.435.455 : 4 bytes 268.435.456 - max-int32 : 5 bytes Here's C# implementations for both: void Main() { using (FileStream stream = new FileStream(#"c:\temp\test.dat", FileMode.Create)) using (BinaryWriter writer = new BinaryWriter(stream)) writer.EncodeInt32(123456789); using (FileStream stream = new FileStream(#"c:\temp\test.dat", FileMode.Open)) using (BinaryReader reader = new BinaryReader(stream)) reader.DecodeInt32().Dump(); } // Define other methods and classes here public static class Extensions { /// <summary> /// Encodes the specified <see cref="Int32"/> value with a variable number of /// bytes, and writes the encoded bytes to the specified writer. /// </summary> /// <param name="writer"> /// The <see cref="BinaryWriter"/> to write the encoded value to. /// </param> /// <param name="value"> /// The <see cref="Int32"/> value to encode and write to the <paramref name="writer"/>. /// </param> /// <exception cref="ArgumentNullException"> /// <para><paramref name="writer"/> is <c>null</c>.</para> /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <para><paramref name="value"/> is less than 0.</para> /// </exception> /// <remarks> /// See <see cref="DecodeInt32"/> for how to decode the value back from /// a <see cref="BinaryReader"/>. /// </remarks> public static void EncodeInt32(this BinaryWriter writer, int value) { if (writer == null) throw new ArgumentNullException("writer"); if (value < 0) throw new ArgumentOutOfRangeException("value", value, "value must be 0 or greater"); do { byte lower7bits = (byte)(value & 0x7f); value >>= 7; if (value > 0) lower7bits |= 128; writer.Write(lower7bits); } while (value > 0); } /// <summary> /// Decodes a <see cref="Int32"/> value from a variable number of /// bytes, originally encoded with <see cref="EncodeInt32"/> from the specified reader. /// </summary> /// <param name="reader"> /// The <see cref="BinaryReader"/> to read the encoded value from. /// </param> /// <returns> /// The decoded <see cref="Int32"/> value. /// </returns> /// <exception cref="ArgumentNullException"> /// <para><paramref name="reader"/> is <c>null</c>.</para> /// </exception> public static int DecodeInt32(this BinaryReader reader) { if (reader == null) throw new ArgumentNullException("reader"); bool more = true; int value = 0; int shift = 0; while (more) { byte lower7bits = reader.ReadByte(); more = (lower7bits & 128) != 0; value |= (lower7bits & 0x7f) << shift; shift += 7; } return value; } }
You should first make an histogram of your value. If the distribution is random (that is, every bin of your histogram's count is close to the other), then you'll not be able encode more efficiently than the binary representation for this number. If your histogram is unbalanced (that is, if some values are more present than others), then it might make sense to choose an encoding that's using less bits for these values, while using more bits for the other -unlikely- values. For example, if the number you need to encode are 2x more likely to be smaller than 15 bits than larger, you can use the 16-th bit to tell so and only store/send 16 bits (if it's zero, then the upcoming byte will form a 16-bits numbers that can fit in a 32 bits number). If it's 1, then the upcoming 25 bits will form a 32 bits numbers. You loose one bit here but because it's unlikely, in the end, for a lot of number, you win more bits. Obviously, this is a trivial case, and the extension of this to more than 2 cases is the Huffman algorithm that affect a "code word" that close-to optimum based on the probability of the numbers to appear. There's also the arithmetic coding algorithm that does this too (and probably other). In all cases, there is no solution that can store random value more efficiently than what's being done currently in computer memory. You have to think about how long and how hard will be the implementation of such solution compared to the saving you'll get in the end to know if it's worth it. The language itself is not relevant here.
If small values are more common than large ones you can use Golomb coding.
I know this question was asked quite a few years ago, however for MIDI developers I thought to share some code from a personal midi project I'm working on. The code block is based on a segment from the book Maximum MIDI by Paul Messick (This example is a tweaked version for my own needs however, the concept is all there...). public struct VariableLength { // Variable Length byte array to int public VariableLength(byte[] bytes) { int index = 0; int value = 0; byte b; do { value = (value << 7) | ((b = bytes[index]) & 0x7F); index++; } while ((b & 0x80) != 0); Length = index; Value = value; Bytes = new byte[Length]; Array.Copy(bytes, 0, Bytes, 0, Length); } // Variable Length int to byte array public VariableLength(int value) { Value = value; byte[] bytes = new byte[4]; int index = 0; int buffer = value & 0x7F; while ((value >>= 7) > 0) { buffer <<= 8; buffer |= 0x80; buffer += (value & 0x7F); } while (true) { bytes[index] = (byte)buffer; index++; if ((buffer & 0x80) > 0) buffer >>= 8; else break; } Length = index; Bytes = new byte[index]; Array.Copy(bytes, 0, Bytes, 0, Length); } // Number of bytes used to store the variable length value public int Length { get; private set; } // Variable Length Value public int Value { get; private set; } // Bytes representing the integer value public byte[] Bytes { get; private set; } } How to use: public void Example() { //Convert an integer into a variable length byte int varLenVal = 480; VariableLength v = new VariableLength(varLenVal); byte[] bytes = v.Bytes; //Convert a variable length byte array into an integer byte[] varLenByte = new byte[2]{131, 96}; VariableLength v = new VariableLength(varLenByte); int result = v.Length; }
As Grimbly pointed out, there exists BinaryReader.Read7BitEncodedInt and BinaryWriter.Write7BitEncodedInt. However, these are internal methods that one cannot call from a BinaryReader or -Writer object. However, what you can do is take the internal implementation and copy it from the reader and the writer: public static int Read7BitEncodedInt(this BinaryReader br) { // Read out an Int32 7 bits at a time. The high bit // of the byte when on means to continue reading more bytes. int count = 0; int shift = 0; byte b; do { // Check for a corrupted stream. Read a max of 5 bytes. // In a future version, add a DataFormatException. if (shift == 5 * 7) // 5 bytes max per Int32, shift += 7 throw new FormatException("Format_Bad7BitInt32"); // ReadByte handles end of stream cases for us. b = br.ReadByte(); count |= (b & 0x7F) << shift; shift += 7; } while ((b & 0x80) != 0); return count; } public static void Write7BitEncodedInt(this BinaryWriter br, int value) { // Write out an int 7 bits at a time. The high bit of the byte, // when on, tells reader to continue reading more bytes. uint v = (uint)value; // support negative numbers while (v >= 0x80) { br.Write((byte)(v | 0x80)); v >>= 7; } br.Write((byte)v); } When you include this code in any class of your project, you'll be able to use the methods on any BinaryReader/BinaryWriter object. They've only been slightly modified to make them work outside of their original classes (for example by changing ReadByte() to br.ReadByte()). The comments are from the original source.
BinaryReader.Read7BitEncodedInt Method ? BinaryWriter.Write7BitEncodedInt Method ?
C# get and set the high order word of an integer
What's an efficient or syntactically simple way to get and set the high order part of an integer?
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. 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
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.
I guess you don't want calculations when you want the Hiword / Hibyte or the LoWord / Lobyte, if a System.Int32 starts at address 100 (so it occupies address 100 to 103), you want as a LoWord the two bytes starting at address 100 and 101 and Hiword is address 102 and 103. This can be achieved using the class BitConverter. This class doesn't do anything with the bits, it only uses the addresses to return the requested value. As the size of types like int / long are different per platform, and WORD and DWORD are a bit confusing, I use the System types System.Int16/Int32/Int64. No one will ever have any problems guessing the number of bits in a System.Int32. With BitConverter you can convert any integer to the array of bytes starting on that location and convert an array of bytes of the proper length to the corresponding integer. No calculations needed and no bits will change, Suppose you have a System.Int32 X (which is a DWORD in old terms) LOWORD: System.Int16 y = BitConverter.ToInt16(BitConverter.GetBytes(x), 0); HIWORD: System.Int16 y = BitConverter.ToInt16(BitConverter.GetBytes(x), 2); The nice thing is that this works with all lengths, you don't have to combine functions like LOBYTE and HIWORD to get the third byte: HIByte(Hiword(x)) will be like: BitConverter.GetBytes(x)[3]
Another Alternative 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)); } }
I use these 2 function... 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); }