In my app, I'm storing Bitmap
data in a two-dimensional integer array (int[,]
). To access the R, G and B values I use something like this:
// read:
int i = _data[x, y];
byte B = (byte)(i >> 0);
byte G = (byte)(i >> 8);
byte R = (byte)(i >> 16);
// write:
_data[x, y] = BitConverter.ToInt32(new byte[] { B, G, R, 0 }, 0);
I'm using integer arrays instead of an actual System.Drawing.Bitmap
because my app runs on Windows Mobile devices where the memory available for creating bitmaps is severely limited.
I'm wondering, though, if it would make more sense to declare a structure like this:
public struct RGB
{
public byte R;
public byte G;
public byte B;
}
... and then use an array of RGB
instead of an array of int
. This way I could easily read and write the separate R, G and B values without having to do bit-shifting and BitConverter-ing. I vaguely remember something from days of yore about byte
variables being block-aligned on 32-bit systems, so that a byte
actually takes up 4 bytes of memory instead of just 1 (but maybe this was just a Visual Basic thing).
Would using an array of structs (like the RGB
example` above) be faster than using an array of ints, and would it use 3/4 the memory or 3 times the memory of ints?
Structure due to use defined data type become slow in performance as access and searching of element is slower in Structure as compare to Array. On other hand in case of Array access and searching of element is faster and hence better in performance.
Advantages of Structure over Array:The structure can store different types of data whereas an array can only store similar data types. Structure does not have limited size like an array. Structure elements may or may not be stored in contiguous locations but array elements are stored in contiguous locations.
Definition. Array is a data structure consisting of a collection of elements each identified by the array index while structure is a data type that stores different data types in the same memory location. Thus, this is the main difference between Array and Structure in C programming.
A structure works similar to an array, where we just pack the values next to each other in memory. Structures are useful because, just like with arrays, they allow us to semantically move many related values with a single pointer.
If you are on about speed, then technically I would expect the int[]
version to be faster, as there is a specific IL instruction for getting an int
from an array (see OpCodes.Ldelem_I4
). To do a custom struct it has to get the address (OpCodes.Ldelema
) and then copy the struct (OpCodes.Ldobj
) - processing the type metadata for both of those steps.
In short - the int
approach should have better optimisations. But this is micro-optimisation - in general prefer the version that makes your code more readable. What you might consider is writing the struct with a custom static implicit conversion operator from int
to your struct - then you can have the int[]
and still do:
MyColor col = intArr[12];
(it'll do a static call in the middle, of course)
You might also consider using a union so you don't need to do lots of shifting:
IMPORTANT I haven't sanity checked the endianness on this; just change the offsets of R/G/B to change it.
class Program
{
static void Main()
{
int[] i = { -1 };
RGB rgb = i[0];
}
}
[StructLayout( LayoutKind.Explicit)]
public struct RGB
{
public RGB(int value) {
this.R = this.G = this.B = 0; this.Value = value;
}
[FieldOffset(0)]
public int Value;
[FieldOffset(2)]
public byte R;
[FieldOffset(1)]
public byte G;
[FieldOffset(0)]
public byte B;
public static implicit operator RGB(int value) {
return new RGB(value);
}
public static implicit operator int(RGB value) {
return value.Value;
}
}
A lone byte on its own would probably get block-aligned, but multiple bytes in a struct can be packed. And according to Marshal.SizeOf, your RGB struct does indeed occupy only three bytes of memory. (Technically, this is the size when marshalling to unmanaged memory, and the CLR could choose to lay it out differently; but in practice I think this will be correct.)
However, the CLR could still insert padding between RGBs and other structs, and this behaviour may depend on the processor, CLR version etc. On a x86 system, allocating an array of 300 million RGB resulted in Task Manager reporting approximately 900 MB committed, whereas allocating an array of 300 million ints resulted in 1200 MB committed. So it looks like the 2.0 CLR on x86 is giving you the 25% saving. (I have to admit this surprised me; like Traveling Tech Guy, I expected the 3-byte structs to be aligned to a 4-byte boundary. So I may be missing something.) But the CF may be different: you'll really only know by testing it on your target platform.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With