entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

2votos

[Codigo C] Struct con array de 1 bit de tamaño en cada posicion

Como dice el titulo, intento en C, crear un array donde cada posicion del mismo, tenga una longitud de 1 bit.

El problema es el siguiente, necesito una forma de listar todos los puertos, y que cada puerto tenga 2 estados. Cerrado (0), o abierto (1). Para ello, solo necesito un bit de memoria por puerto.

Lo intenté de la siguiente manera:

typedef struct{
      int ports:1 [65535];
}ports;

Pero no funciona. Otra solucion posible era:

 typedef struct{
        int 1:1;
        int 2:1;
        int 3:1;
        int 4:1;
        .
        .
        .
        int 65535:1;
    }ports;

Y obtener el resultado con un simple:
ports.N
Donde N es el numero de puerto

Pero por razones obvias, quiero buscar una solucion mejor que escribir los 65535 puertos y quedarme sin manos en el proceso ._.

¿Alguna idea?

3 Respuestas

3votos

Leonardo-Tadei Puntos227320

Hola Facu-Curti,

vamos por partes. Por un lado, no puede tener una variable en C que ocupe solo un bit, ya que el mínimo tamaño que C puede direccionar es de 1 byte.

En este caso, podrías tener un array de bytes y asignarles valores de 0 y 1 (o V y F, o O y C [Open / Close])

Podrías complicarte la vida o montar todo esto sobre un unsigned long que va desde 0 a 2 mil millones y pico, y trabajar con operaciones de corrimiento de bits y un poco de álgebra boleana para que cada 0 y 1 que en binario forman estos 2 bytes, tenga para tu software el sentido semántico que corresponde a un puerto abierto o cerrado, según la posición del 0 y 1 que ocupan, que en definitiva será algo así como 000011000... para representar que están abiertos los puertos de PING, FTP DATA y FTP (7+20+21)... pero para mi gusto es demasiado complicado y salvo que estés trabajando con software embebido o algún tipo de hardware mínimo, lo evitaría.

Para no consumir toda la memoria de un tirón en la asignación, creo que lo mejor es un arreglo dinámico en el que por ejemplo guardarás solo los puertos abiertos (que deberían ser menos que los cerrados) y soportar el costo de agregar elementos dinámicamente. Te dejo acá un enlace con ejemplos de uso y de asignación de espacio: http://es.wikibooks.org/wiki/Programaci%C3%B3n_en_C/Manejo_din%C3%A1mico_de_memoria

En tu caso, haría un aray de punteros a byte, que es el menor espacio que pudés direccionar.

Si los recursos no son un problema, usá directamente un array de char con 65535 posiciones: consumirás 64K de RAM al crearlo, pero el manejo es trivial.

char ports[65535];

ponerlo dentro de un struct o no es ya cuestión de gustos.

Saludos!

0voto

facu-curti comentado

Gracias por la respuesta. Me ha servido mucho, ahora me has dado para pensar jaja. :) Veré de que forma lo hago.

Gracias de nuevo. Un abrazo! ;)

0voto

facu-curti comentado

Un profe mio me dio una idea que creo es mejor. Se trata de crear un struct de 8 bits.

struct bits{
   unsigned char b0:1;
   unsigned char b1:1;
   unsigned char b2:1;
   unsigned char b3:1;
   unsigned char b4:1;
   unsigned char b5:1;
   unsigned char b6:1;
   unsigned char b7:1;
}
struct bits puertos[8192];

Entonces accedo a los puertos con alguna funcion matematica. por ejemplo, el puerto numero 12 seria el quinto bit del segundo elemento del arreglo. Y se podria calcular con una funcion de la siguiente forma:

12/8=1.5
1 es el elemento del array.
Y para sacar la posicion del bit:
(1.5 - 1)*8 = 4
y luego para acceder al elemento correspondiente tendria que usar un switch.

Es medio liado, pero me parece mas sencillo que usar el long int, o incluso, mas sencillo que usar memoria dinamica.

Gracias a todos! :)

0voto

Leonardo-Tadei comentado

Hola Facu,

Es una solución equivalente a la de crear un array de 65535 caracteres, pero con un poco más de estructura, lo cual puede ser bueno si hay que acceder a los puertos en bloque.

Fijate que la esctructura que comentás está armada con unsigned char, es decir, acupa un byte y no un bit, por lo que también tenés los 64Kb de consumo de RAM al crearla.

Si accederlos de a 8 es mejor solución a tu problema, esta es mejor. Si no tenés que accederlas de a 8, te ganás una complicación al tener que acceder a cada elemento consumiendo los mismos recursos que el array de char.

Saludos y gracias por comentar otra solución más!

0voto

facu-curti comentado

Nono. Por que son solo 8192 posiciones en el array, que ocupan un byte cada una. En total 65535 bits. Y uso bit a bit gracias al struct :) Funciona de 10, y consume 8192 byts

0voto

Leonardo-Tadei comentado

Hola Facu,

perdoname, pero no entiendo algo o estás calculando mal el tamaño:

Cuando ponés:

struct bits{
   unsigned char b0:1;
   unsigned char b1:1;
   unsigned char b2:1;
   unsigned char b3:1;
   unsigned char b4:1;
   unsigned char b5:1;
   unsigned char b6:1;
   unsigned char b7:1;
}

definís el struct "bits" llamado conteniendo 8 unsigned char, un char, ya sea con signo o sin signo, ocupa un BYTE no un BIT.

Luego, al tener 8192 veces esa estructura, que ocupa 8 BYTES, tenés 64K (8192 * 8 BYTES = 65536 BYTES = 64KB ).

Todo es por lo que te digo al principio: no existen en C una variable que ocupe solo un BIT: lo mínimo que puede direccionar es un BYTE.

Saludos!

2votos

Como comenta @facu-curti, se podría hacer algo como:

char puertos[8191];

Luego a la hora de acceder sería una simple operación matemática:

int getPosicionArray(int puerto) {
    if(puerto > 65534 || puerto < 0) {
        printf("El valor del puerto no es correcto");
        return -1;
    }

    return puerto / 8;    //Division entera
}

Por otro lado, necesitarías una función que te diga el bit (de entre los 8 de cada posición) es el que necesitas:

int getPosicionBit(int puerto) {
    if(puerto > 65534 || puerto < 0) {
        printf("El valor del puerto no es correcto");
        return -1;
    }

    return puerto % 8;   //Modulo o resto de la division
}

Por último para recuperar el bit sólo habría que utilizar las dos funciones anteriores:

int getEstadoPuerto(int puerto) {
    if(puerto > 65534 || puerto < 0) {
        printf("El valor del puerto no es correcto");
        return -1;
    }

    int posicionArray = getPosicionArray(puerto);
    int posicionBit = getPosicionBit(puerto);
    return (int) 0x00000001 & (puertos[posicionArray] >> posicionBit);
}

Esa función devolvería 0 y 1 dependiendo del estado del puerto. Para abrir o cerrar un puerto bastaría hacer otro método parecido a getEstadoPuerto pero escribiendo el valor.

Cabría destacar que los puertos irían desde el 0 hasta el 65534. En caso de querer que fuesen desde el 1 hasta el 65535 habría que hacer pequeñas modificaciones.

Con ese código en memoria sólo tendrías 7KB (8191 bytes / 1024), por lo que quizás sería una solución a tener en cuenta.

Saludos.

0voto

facu-curti Puntos220

@Leonardo-Tadei , no. mira:
unsigned char b0:1;

Eso dentro del struct, consume solo 1 bit. Es cierto lo que dices, la direccion minima redireccionable de memoria es de un byte. PERO, se puede trabajar individualmente bit a bit. Gracias a los struct.

En ese struct yo defino 8 lugares de un bit cada uno. Podria haber echo:

struct bits{
   int b0:1;
   int b1:1;
   int b2:1;
   int b3:1;
   int b4:1;
   int b5:1;
   int b6:1;
   int b7:1;
}

Y todo el struct seguria ocupando un byte. Puesto que tiene 8 posiciones de un bit cada uno. El :1 al lado del nombre de la variable, indica la cantidad de bits a ocupar. Podrian haber sido 5, 7 o 100 si quisiera. La definicion como int, o unsigned char, solo se hace para especificar la forma en que se almacenaran los valores dentro de ese bit. Si hubiera puesto float o double, trabajaria de forma diferente, pero seguiria ocupando un bit cada posicion del struct.

Por otro lado, si yo hubiera colocado:

  struct bits{
   unsigned char b0:1;
   unsigned char b1:1;
   unsigned char b2:1;
}

Eso no ocuparía 3 bits, como se puede esperar. Eso ocupa un byte. Por que como dices, es la minima dimension redireccionable. Por lo tanto, el tamaño de un struct, siempre deben ser multiplos de un byte. PERO, se pueden trabajar esos bytes de forma que podamos utilziarlos bit a bit.

Otra solucion que encontre, y a mi parecer mucho mejor, fue la de crear un unsigned char. Y trabajar con esta variable a travez de operaciones de corrimientos de bits. Mira:

    int checkPort(unsigned short int ports, unsigned short int port){
        return (ports & (1 << port));
}

void openPort(unsigned short int* ports, unsigned short int port){
    if ( !checkPort(*ports,port) ){
        *ports ^= (1 << port);
    }
}

void closePort(unsigned short int* ports, unsigned short int port){
    if (checkPort(*ports,port)){
        *ports ^= (1 << port);
    }
}

Con esas 3 funciones, checo el estado, abro, o cierro un puerto, respectivamente.

Gracias a todos, saludos! ;)

0voto

Leonardo-Tadei comentado

Hola Facu,

gracias por la aclaración. La verdad es que no estaba familiarizado con la declaración :1
Hasta este comentario, creí que el operador :1 en la declaración funcionaba como un asignador del tipo 0x01, pero no sabía que también limitaba el tamaño de la variable.

Me tuve que escribir una estructura y ver con sizeof() que mi compilador la resolvía bien y daba el tamaño correcto!

Parece que es parte del standard ANSI pero que no está normalizado... sea esto lo que sea que signifique.

Gracias de nuevo!

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta