I have a need to convert an Int32 value to a 3-byte (24-bit) integer. Endianness remains the same (little), but I cannot figure out how to move the sign appropriately. The values are already constrained to the proper range, I just can't figure out how to convert 4 bytes to 3. Using C# 4.0. This is for hardware integration, so I have to have 24-bit values, cannot use 32 bit.
Asked
Active
Viewed 8,961 times
3
-
What type do you plan on storing the 24-bit integer in? – The Scrum Meister Feb 07 '11 at 06:17
-
A byte array would be just fine. I will be outputting the 3 bytes across a serial connection, so as long as I can get it into bytes, I'm good to go. – drharris Feb 07 '11 at 06:18
-
That third line won't do anything (`i & 0xffffff` is always positive). Also, you might want to follow the second part of Joe's answer that works on systems with different endiannesses; the code you have will work for now but will break in unusual ways if you ever try to run it on a PowerPC or MIPS, for example. – Jeremiah Willcock Feb 07 '11 at 07:08
-
Sorry, my actual code involves setting a `bool` flag when negative. I neglected to realize that line 2 would then make it positive, and so line 3 would never activate. The point was to test the original number for negative. I will update the answer accordingly. And I am accounting for endianness, but I'll make a note in the solution that you should do so. – drharris Feb 07 '11 at 07:11
-
I simply removed my addendum altogether. Any interested party should read the answers. Assuming the 32-bit value is already constrained to the range of a 24-bit integer, the negative sign will always carry over to the 24-bit due to two's complement. All that is left is checking for endianness when you retrieve the byte array. I tried to overcomplicate things. :) – drharris Feb 07 '11 at 07:19
2 Answers
3
If you want to do that conversion, just remove the top byte of the four-byte number. Two's complement representation will take care of the sign correctly. If you want to keep the 24-bit number in an Int32
variable, you can use v & 0xFFFFFF
to get just the lower 24 bits. I saw your comment about the byte array: if you have space in the array, write all four bytes of the number and just send the first three; that is specific to little-endian systems, though.

Jeremiah Willcock
- 30,161
- 7
- 76
- 78
-
Thanks for the info. I'm still not convinced about the sign, since it's typically held within the most significant bit. For example, try the code `Console.Write(-42 & 0xffffff);`. Or am I missing something here? – drharris Feb 07 '11 at 06:44
-
It will just keep the lowest three bytes, which are unsigned (since you are right about the sign bit being in the top byte). However, even with the mask, `42` and `-42` will produce different results after the AND operation. – Jeremiah Willcock Feb 07 '11 at 06:46
-
So, I can do `int bit24 = bit32 & 0xffffff;`, and then do `bit24 |= 0x800000;` if it tests for negative? Basically resetting that sign bit manually? – drharris Feb 07 '11 at 06:48
-
You would want to do `if (bit24 & 0x800000) bit32 = (bit24 | 0xFF000000); else bit32 = bit24;` to restore the sign bit (since all of the top bits need to be set to keep the value when changing to 32 bits). For a 24-bit number, the sign bit is in a different place than for a 32-bit number. – Jeremiah Willcock Feb 07 '11 at 06:50
-
2My bad. I neglected to actually look at the hex for these answers. It turns out that for negative numbers in 32-bit, that the proper bit for 24-bit will indeed always be set due to two's complement (*assuming* the values are indeed constrained to the range of 24 bit). I've tested the full range of negative values in 32-bit, and it's always the case, so simply masking by `0xffffff` will always work. – drharris Feb 07 '11 at 07:15
3
Found this: http://bytes.com/topic/c-sharp/answers/238589-int-byte
int myInt = 800;
byte[] myByteArray = System.BitConverter.GetBytes(myInt);
sounds like you just need to get the last 3 elements of the array.
EDIT:
as Jeremiah pointed out, you'd need to do something like
int myInt = 800;
byte[] myByteArray = System.BitConverter.GetBytes(myInt);
if (BitConverter.IsLittleEndian) {
// get the first 3 elements
} else {
// get the last 3 elements
}

Joe
- 11,147
- 7
- 49
- 60
-
Note that the documentation says that the result of `GetBytes` is in the system's native endianness, so there would need to be a test for that to be portable. I think you meant "first 3 elements" rather than "last 3" for little-endian, too. – Jeremiah Willcock Feb 07 '11 at 06:25
-
good point, but doesn't all 3 answers have the same flaw? or does v & 0xFFFFFF work because the logic is handled in a lower level? – Joe Feb 07 '11 at 06:30
-
1What flaw? Requiring a little-endian system? All of the solutions that write to a byte array seem to require endianness-checking; `v & 0xFFFFFF` is done within a 32-bit word, without needing to know how that is represented as bytes. – Jeremiah Willcock Feb 07 '11 at 06:32
-
Looking at the docs some more, `BinaryReader` and `BinaryWriter` are always little-endian, regardless of the system. There is also a solution at http://snipplr.com/view/15179/adapt-systembitconverter-to-handle-big-endian-network-byte-ordering-in-order-to-create-number-types-from-bytes-and-viceversa/ that allows the endianness to be set. – Jeremiah Willcock Feb 07 '11 at 06:36
-
Looking at the newest change to your answer, I think it's still backwards: you want the first 3 elements for little-endian and the last 3 for big-endian. – Jeremiah Willcock Feb 07 '11 at 06:37
-
ah ok, i understand it now. i've updated my answer to hopefully be endian-correct now :) – Joe Feb 07 '11 at 06:38
-
-
that's cause i took about 5 minutes to write my comment in which you posted 2 more! :) ur too quick. ok how's that? – Joe Feb 07 '11 at 06:41
-
The second part is right, but the part before "EDIT:" still says "last 3". I would recommend getting rid of the old part anyway. – Jeremiah Willcock Feb 07 '11 at 06:42
-
Tough to decide which one to pick, since the generic use case (bit masking) is properly handled by Jeremiah's answer, but in the end I did need a byte array. Despite knowing this particular method already, it did provide some good information to future people with a similar problem. Final answer explained in the original post's edit. – drharris Feb 07 '11 at 07:06