2010-08-27 8 views
5

Was ich meine ist, sagen, ich habe ein struct einige Daten zu repräsentieren, und es sieht wie folgt aus:Wenn ich drei separate Werte habe, die alle in 32 Bits passen könnten, macht es Sinn, sie zu speichern?

struct LilStruct 
{ 
    public readonly short A; 
    public readonly byte B; 
    public readonly byte C; 

    public LilStruct(short a, byte b, byte c) 
    { 
     A = a; 
     B = b; 
     C = c; 
    } 
} 

A short und zwei byte Werte alle in 32 Bits passen könnte. Was ich frage mich, ist (für Zwecke der Ausrichtung, Leistung, was auch immer), wenn es würde tatsächlich Sinn machen, diese Daten in folgendem Format zu speichern, statt:

struct LilStruct 
{ 
    private readonly uint _value; 

    public LilStruct(short a, byte b, byte c) 
    { 
     _value = ((uint)a << 16) | ((uint)b << 8) | (uint)c; 
    } 

    public int A 
    { 
     get { return (int)(_value >> 16); } 
    } 

    public int B 
    { 
     get { return (int)(_value >> 8) & 0x000000FF; } 
    } 

    public int C 
    { 
     get { return (int)(_value & 0x000000FF); } 
    } 
} 

Ist das sinnlos? Was wären die Vorteile/Nachteile?

+1

unabhängig von der Antwort, ich denke, es ist großartig, das wurde angesprochen. Ich persönlich finde es gut, pragmatisch zu sein. – DevSolo

Antwort

3

In .NET, wenn Sie eine struct sowieso verwenden wollen, können Sie als dekorieren auch die Struktur mit StructLayoutAttribute wie folgt aus:

[StructLayout(LayoutKind.Sequential, Pack=1)] 
struct LilStruct 
{ 
    public readonly short A; 
    public readonly byte B; 
    public readonly byte C; 

    public LilStruct(short a, byte b, byte c) 
    { 
     A = a; 
     B = b; 
     C = c; 
    } 
} 

Dies wird den Effekt haben, dass die Felder sequentiell angelegt, z.B Das Feld B fängt bei Offset 16 an.

Ein Wert von 1 für Pack bedeutet, dass die Felder an den Grenzen byte ausgerichtet sind.

+0

Ah! Sehr nützlich zu wissen! –

0

Worauf Sie stoßen werden, ist ein einfacher Kompromiss zwischen der Größe Ihrer In-Memory-Datenobjekte und den Kosten der Verarbeitung. Wenn Speicher ein echtes Problem ist, kann es einfach billiger sein, mehr RAM auf Ihrem Computer zu werfen.

2

Sie sollten nur in Betracht ziehen, mehrere Werte in eine Uint zu puffern, wenn die Werte eng miteinander verknüpft sind, normalerweise zusammen weitergegeben werden und niemals oder sehr selten unabhängig voneinander geändert werden. Die Kosten für das Entpacken und Umpacken der Uint, um ihren Wert zu ändern, machen dies sehr teuer (in Code-Größe und Ausführungszeit) im Vergleich zu nur drei Bytes getrennt zu speichern.

Bei der Ausführung auf einem Mikrogerät mit insgesamt 10 kbyte RAM könnte es sich lohnen, so zu packen, weil der Speicher wertvoller ist als die Ausführungsgeschwindigkeit. Auf einem normalen Desktop-PC oder sogar Handy-Gerät ist diese Verpackung wahrscheinlich nicht die Mühe wert.

1

Sie könnten mit Ihrer Strukturdefinition bleiben und das StructLayout Attribut mit einem StructLayoutAttribute.Pack Wert von 1 anwenden. Aber in der Tat sparen Sie wahrscheinlich ein wenig Speicher auf Kosten der Zugriffsgeschwindigkeit, da auf diese Weise die Daten würden nicht in einer Weise angelegt werden, die am effizientesten zugänglich ist. Der Compiler würde den Speicher normalerweise so anlegen, dass er effizient zugreift und nicht zu viel Speicher automatisch verderben würde. Dieser Ansatz würde zumindest Ihren Code verständlicher machen als den von Ihnen vorgeschlagenen Bit-Shifting-Ansatz (der in Wirklichkeit vielleicht noch ähnlich dem ist, was der Maschinencode-Compiler aus dem Byte-Code generieren würde).

0

Es gibt ein paar Fälle, in denen es sich lohnt, Sachen in eine Ganzzahl zu stopfen. Speicherplatz allein ist normalerweise kein guter Grund, aber wenn die Werte zusammen verwendet werden, wie z. Ein Schlüssel für ein Dictionary, ein Dictionary (Of Integer, Whatever) ist viel schneller als ein Dictionary (Of SomeStructure, Whatever).