Pregunta

Estoy tratando de almacenar una gran cantidad de booleanos de la información que se determina en tiempo de ejecución.Me pregunto cuál es el mejor método podría ser.

He estado tratando de asignar la memoria mediante:

pStatus = malloc((<number of data points>/8) + 1);

pensando que esto me dará suficientes bits para trabajar con.Entonces yo podría referencia de cada valor booleano utilizando el puntero en la notación de matriz:

pStatus[element]

Por desgracia, esto no parece estar funcionando muy bien.En primer lugar, estoy teniendo dificultades para inicializar la memoria al valor entero 0.Se puede hacer esto usando memset()?Aún así, no creo que está impactando por qué me fallo al intentar acceder a pStatus[element].

No estoy totalmente convencido de que este enfoque es el mejor para usar.Lo que realmente quiero es esencialmente un gigante de la máscara de bits que refleja el estado de los valores booleanos.He perdido de algo?

¿Fue útil?

Solución

pStatus = malloc((<number of data points>/8) + 1);

Esto asigna suficientes bytes para sus bits. Sin embargo,

pStatus[element]

Esto accede al elemento'th byte , no bit. Entonces, cuando el elemento es más de un octavo del número total de bits, está accediendo desde el final de la matriz asignada.

Definiría algunas funciones auxiliares

int get_bit(int element)
{
    uint byte_index = element/8;
    uint bit_index = element % 8;
    uint bit_mask = ( 1 << bit_index);

    return ((pStatus[byte_index] & bit_mask) != 0);
}

void set_bit (int element)
{
    uint byte_index = element/8;
    uint bit_index = element % 8;
    uint bit_mask = ( 1 << bit_index);

    pStatus[byte_index] |= bit_mask);
}

void clear_bit (int element)
{
    uint byte_index = element/8;
    uint bit_index = element % 8;
    uint bit_mask = ( 1 << bit_index);

    pStatus[byte_index] &= ~bit_mask;
}

(error al verificar el rango del elemento que queda fuera para mayor claridad. También podría hacer estas macros)

Otros consejos

... pensando que esto me dará suficientes bits para trabajar. Entonces podría hacer referencia a cada valor booleano utilizando el puntero en notación de matriz:

pStatus[element]
El elemento

se dirige a bytes , no a bits. Quieres algo como:

pStatus[element/8] & (1 << (element % 8))

Punto pequeño: para obtener suficiente memoria para almacenar N bits, (N / 8) + 1 bytes es impreciso (puede ser demasiado).

(N + 7) / 8 siempre es el número mínimo, sin embargo.

Bueno, la respuesta más simple sería usar calloc en lugar de malloc.

Está definido para inicializar la memoria que asigna a cero, y a menudo puede hacerlo utilizando trucos de mapeo de páginas.

Eso se encargará de su problema de inicialización de memoria. La otra docena de publicaciones aquí parecen abordar adecuadamente el problema de indexación y el hecho de que ocasionalmente asigna un byte adicional (¡oh, el horror!), Por lo que no repetiré su contenido aquí.

pStatus [element] le dará un byte completo en esa dirección.

Para establecer un elemento particular, haría algo como:

pStatus[element >> 3] |= 1 << (element & 7);

Para restablecer un elemento:

pStatus[element >> 3] &= ~1 << (element & 7);

y para probar un elemento:

if (pStatus[element >> 3] & (1 << (element & 7)) != 0)

la asignación inicial debe ser

pstatus = malloc((<number of data points> + 7) / 8)

lo que tenía funcionará pero ocasionalmente desperdicia un byte

No puedo evitar notar que todas las respuestas en C aquí parecen suponer que un byte es de 8 bits. Esto no es necesariamente cierto en C (aunque, por supuesto, será cierto en la mayoría del hardware convencional), por lo que hacer esta suposición en el código es bastante mala.

La forma correcta de escribir código de arquitectura neutral es

#include <limits.h>

y luego use la macro CHAR_BIT donde sea que necesite " el número de bits en un char " ;.

Hazte más feliz y define un tipo y funciones para operar en ese tipo. De esa manera, si descubre que los accesos de bits son demasiado lentos, puede cambiar la unidad de memoria por booleano a un byte / palabra / largo o adoptar estructuras de datos dispersas / dinámicas si la memoria es realmente un problema (es decir, si sus conjuntos son en su mayoría ceros , podría mantener una lista con las coordenadas de los 1.

Puede escribir su código para que sea completamente inmune a los cambios en la implementación de su vector de bits.

pStatus [elemento] no direcciona el bit. El byte exacto que obtiene depende del tipo de pStatus, supongo que char * o equivalente, por lo que pStatus [element] le proporciona el byte del elemento.

Podrías establecer un memset en 0, sí.

 pStatus = malloc((<number of data points>/8) + 1);

Esa parte está bien.

 pStatus[element]

aquí es donde tienes problemas. Son bytes de dirección, cuando quieren direccionar bits.

 pStatus[element / 8 ]  

obtendrá el byte correcto en la matriz.

Debe asignar c = malloc((N+7)/8) bytes y puede establecer el enésimo con

 c[n/8]=((c[n/8] & ~(0x80 >> (n%8))) | (0x80>>(n%8)));

borrar con

 c[n/8] &= ~(0x80 >> (n%8));

y prueba con

 if(c[n/8] & (0x80 >> (n%8))) blah();

Si no le importa tener que escribir envoltorios, también puede usar bit_set o bit_vector del STL de C ++, parece que (especialmente el último) tienen exactamente lo que necesita, ya codificado, probado y empaquetado (y un montón de campanas y silbatos).

Es una verdadera lástima que carezcamos de una forma directa de usar el código C ++ en aplicaciones C (no, crear un contenedor no es sencillo para mí, ni divertido, y significa más trabajo a largo plazo).

¿Qué estaría mal con std::vector<bool>?

Me sorprende que solo una respuesta aquí mencione CHAR_BIT. Un byte suele ser de 8 bits, pero no siempre.

Usted asignación de código es correcto, consulte la set_bit() y get_bit() funciones dadas en esta respuesta para acceder a la booleano.

Si está limitado a solo unos pocos bits, en lugar de la solución eaanon01, también puede usar la función incorporada c de bitfield (hay muy pocas ocasiones en las que podría usarlos, pero este sería uno)

Para este tipo de golpes, puedo recomendar: Herny Warrens & Quot; Hacker Delight & Quot;

El booleano es " nunca " un valor separado en C. Por lo tanto, una estructura podría ser para que pueda comenzar.

Es cierto que no inicializa el área de memoria, por lo que debe hacerlo individualmente.

Aquí hay un ejemplo simple de cómo podría hacerlo con estructuras de estructuras y enumeraciones

typedef unsigned char           BYTE;
typedef unsigned short          WORD;
typedef unsigned long int       DWORD;
typedef unsigned long long int  DDWORD;
enum STATUS
{
    status0 = 0x01,
    status1 = 0x02,
    status2 = 0x04,
    status3 = 0x08,
    status4 = 0x10,
    status5 = 0x20,
    status6 = 0x40,
    status7 = 0x80,
status_group = status0 + status1 +status4
};
#define GET_STATUS( S ) ( ((status.DDBuf&(DDWORD)S)==(DDWORD)S) ? 1 : 0  )
#define SET_STATUS( S ) (  (status.DDBuf|=  (DDWORD)S) )
#define CLR_STATUS( S ) (  (status.DDBuf&= ~(DDWORD)S) )
static union {
 BYTE   BBuf[8];
 WORD   WWBuf[4];
 DWORD  DWBuf[2];
 DDWORD DDBuf;
}status;

int main(void)
{
    // Reset status bits
    status.BBuf[0] = 0;
    printf( "%d \n", GET_STATUS( status0 ) );

    SET_STATUS( status0 );
    printf( "%d \n", GET_STATUS( status0 ) );

    CLR_STATUS(status0);
    printf( "%d \n", GET_STATUS( status0 ) );
    SET_STATUS( status_group );
    printf( "%d \n", GET_STATUS( status0 ) );
    system( "pause" );
    return 0;
}

Espero que esto ayude. Este ejemplo puede manejar hasta 64 booleanos de estado y podría extenderse fácilmente.

Este ejemplo se basa en Char = 8 bits int = 16 bits de largo int = 32 bits y largo largo int = 64 bits

Ahora también he agregado soporte para grupos de estado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top