2010-08-27 10 views
5

Lo que quiero decir es, decir que tengo un struct para representar algunos datos y se ve así:Si tengo tres valores separados que podrían caber en 32 bits, ¿tiene sentido usar un uint para almacenarlos?

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 y dos byte valores podrían encajar en todos los 32 bits. Lo que me pregunto es (para la alineación, el rendimiento, lo que sea) si sería realmente tiene sentido para almacenar estos datos en el formato siguiente en su lugar:

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

Es este sentido? ¿Cuáles serían los beneficios/inconvenientes?

+1

independientemente de la respuesta, creo que es grandioso que esto se haya planteado. Personalmente, creo que es bueno ser pragmático. – DevSolo

Respuesta

3

En .NET, cuando se va a utilizar un struct de todos modos, se puede así decorar la estructura con StructLayoutAttribute así:

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

Esto tendrá el efecto de que los campos se disponen secuencialmente, p.ej campo B comenzará en el desplazamiento 16.

Un valor de 1 para Pack significa que los campos están alineados en los límites byte.

+0

¡Ah! ¡Muy útil para saber! –

0

Lo que encontrará es una simple compensación entre el tamaño de sus objetos de datos en memoria y el costo de procesamiento. Si la memoria es una preocupación real, puede ser más barato tirar más RAM en su máquina.

2

Debería considerar incluir múltiples valores en un uint si los valores están estrechamente relacionados entre sí, generalmente pasados ​​juntos, y nunca o muy raramente se modifican independientemente el uno del otro. El costo de desempaquetar y volver a embalar el uint para modificar su valor lo hace muy costoso (en cuanto al tamaño del código y el tiempo de ejecución) en comparación con solo almacenar tres bytes por separado.

Al ejecutar en un microdispositivo con un total de 10k bytes de RAM, un embalaje como este podría valer la pena, ya que la memoria es más valiosa que la velocidad de ejecución. En una PC de escritorio normal o incluso en un dispositivo de teléfono móvil, este embalaje probablemente no valga la pena.

1

que podría permanecer con su definición, estructura, y aplicar el atributo StructLayout con un valor de StructLayoutAttribute.Pack 1. Pero, de hecho, es probable que ahorrar un poco de memoria a expensas de la velocidad de acceso, ya que de esta manera los datos se no se debe presentar en la memoria de una manera que sea más eficiente de acceder. El compilador normalmente tendía la memoria de forma eficiente para acceder y no arruinaba demasiada memoria automáticamente.

Este enfoque al menos mantendría su código más comprensible que el enfoque de cambio de bit que propuso (que de hecho podría ser similar a lo que el compilador de código de máquina generaría a partir del código de bytes).

0

Hay algunos casos en los que vale la pena incluir cosas en un número entero. Por sí solo, el espacio de almacenamiento no es una buena razón, pero si los valores se van a usar juntos, como p. una clave para un diccionario, un diccionario (de entero, lo que sea) será mucho más rápido que un diccionario (de alguna estructura, lo que sea).

Cuestiones relacionadas