es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Registrar un submódulo en un módulo principal con una macro del preprocesador C

Estoy implementando un pequeño sistema en C para un microcontrolador. Este sistema tiene múltiples sensores. Inspirado por el kernel de Linux, me gustaría crear un módulo llamado “sensors-core” y sensores separados para cada tipo de sensor.

Cuando se implementa un nuevo módulo en el kernel, hay una macro llamada “module_init”. Esta macro toma un puntero a una estructura y lo guarda en la sección de memoria predefinida. Al iniciar el kernel, todas las funciones init de todos los módulos son llamadas, una por una, basándose en esa sección de memoria con punteros a funciones.

Estoy intentando hacer algo similar con mis módulos de sensores y sensor-core. Digamos que mi módulo “sensors-core” tiene un arreglo de punteros. Cada sensor crea su propia estructura de configuración. Me gustaría escribir una macro que copie el puntero de dicha estructura y lo coloque en el arreglo del módulo “sensors-core”, todo en tiempo de compilación.

sensors-core.h:

struct sensor_config {
    void (*init)(void) init;
    ...
};

sensors-core.c:

#include "sensors-core.h"

struct sensor_config *sensors[SENSORS_MAX_NUM];

sensor.c

#include "sensors-core.h"

void Init(void) {
    ...
}

struct sensor_config config = {
    .init = Init
};

SENSOR_INIT(config);
  1. ¿Cómo puedo escribir dicha macro? ¿Es posible? ¿Dependerá del compilador o puedo hacerlo de manera portable?
  2. ¿Puede el preprocesador encargarse de cuántas veces se usa la macro SENSOR_INIT() y ajustar dinámicamente (en tiempo de compilación) el tamaño del arreglo de sensores? Sé que un arreglo de memoria puede ser un desperdicio. En el kernel de Linux, después de la inicialización, la sección de memoria que contiene la lista de punteros es liberada para otro uso. En este momento no me preocupo por eso, sería el siguiente paso.

Encontré algo similar pero no es exactamente la solución que estoy buscando. Aquí podemos agregar un atributo a una función para que se llame antes de “main”.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Respuesta

    1. Para escribir dicha macro, puedes utilizar __attribute__((constructor)) en GCC. Este atributo te permite especificar la prioridad de la función que se llamará al inicio del programa, al igual que module_init() en el kernel de Linux. Esto debería funcionar en diferentes compiladores de GCC. Aquí tienes un ejemplo de cómo definir la macro SENSOR_INIT():
    #define SENSOR_INIT(config) \
    static void __attribute__((constructor)) sensor_init_fn_##config() \
    { \
        static struct sensor_config *p = &config; \
        int i; \
        /* Encuentra la primera ranura vacía en el arreglo de sensores */ \
        for (i = 0; i < SENSORS_MAX_NUM && sensors[i] != NULL; i++); \
        /* Si no hay ranuras vacías, este sensor no se agregará */ \
        if (i < SENSORS_MAX_NUM) \
            sensors[i] = p; \
        else \
            printf("ERROR: No se puede agregar el sensor %s, demasiados sensores\n", #config); \
    }
    
    1. El preprocesador no puede ajustar dinámicamente el tamaño del arreglo en tiempo de compilación basado en el número de macros SENSOR_INIT() utilizadas en el código. Deberás establecer manualmente la constante SENSORS_MAX_NUM para que sea lo suficientemente grande como para contener todos los posibles sensores o utilizar la asignación dinámica de memoria para asignar el arreglo sensors en tiempo de ejecución.

Comments are closed.