16 votos

Posibilidades para la asignación de memoria para modular el firmware de diseño en C

modular enfoques son bastante útil en general (portátiles y limpio), así que intenta programa de módulos independientes de cualquiera de los otros módulos como sea posible. La mayoría de mis planteamientos se basan en una estructura que describe el propio módulo. Una función de inicialización de los conjuntos de la primaria parámetros, después de un controlador (puntero a desriptive struct) se pasa a cualquier función dentro del módulo se llama.

Ahora, me pregunto cuál es el mejor enfoque de la asignación de memoria para la estructura que describe un módulo puede ser. Si es posible, me gustaría que las siguientes:

  • Opaco de la estructura, de modo que la estructura sólo puede ser alterado por el uso de las funciones de interfaz
  • Varias instancias
  • la memoria asignada por el enlazador

Veo las siguientes posibilidades, que todos los conflictos con uno de mis objetivos:

declaración global

varias instancias, allcoted por enlazador, pero la estructura no es opaco

(#includes)
module_struct module;

void main(){
   module_init(&module);
}

malloc

opaco struct, varias instancias, pero allcotion en montón

en el módulo.h:

typedef module_struct Module;

en el módulo.c función init, malloc y volver puntero a la memoria asignada

module_mem = malloc(sizeof(module_struct ));
/* initialize values here */
return module_mem;

en principal.c

(#includes)
Module *module;

void main(){
    module = module_init();
}

declaración en el módulo

opaco struct, asignados por el enlazador, sólo un número predefinido de instancias

mantener toda la estructura y la memoria interna del módulo y nunca exponga a un controlador o estructura.

(#includes)

void main(){
    module_init(_no_param_or_index_if_multiple_instances_possible_);
}

Hay una opción para combinar estos de alguna manera para opaca struct, enlazador en lugar de la asignación del montón y múltiples/cualquier número de instancias?

21voto

GetFree Puntos 495

I programa de pequeñas micro-controladores en C++, que consigue exactamente lo que quiere.

Lo que usted llama un módulo es una clase de C++, que puede contener datos (ya sea externamente accesible o no) y funciones (del mismo modo). El constructor (de una función dedicada) initilializes. El constructor puede tomar parámetros de tiempo de ejecución o (mi favorito) en tiempo de compilación (plantilla) de los parámetros. Las funciones dentro de la clase implícitamente obtener la variable de clase como primer parámetro. (O, a menudo, mi preferencia, la clase puede actuar como un oculto singleton, por lo que todos los datos se accede sin esta sobrecarga).

El objeto de la clase puede ser global (así que usted sabe que en el enlace-momento en el que todo se ajuste a), o en la pila local, presumiblemente en el principal. (No me gusta C++ globales debido a la indefinidos global de inicialización de la orden, así que prefiero pila-local).

Mi preferido el estilo de programación es que los módulos son las clases estáticas, y de su (estática) de configuración es por los parámetros de la plantilla. Esto evita que casi todos los overhad y permite la optimización. Combine esto con una herramienta que calcula el tamaño de la pila y se puede dormir sin preocupaciones :)

Mi charla sobre esta forma de codificación en C++: Objetos? No, Gracias!

Un montón de embedded / microcontrolador programadores parecen no gustar de C++ porque piensan que eso les obligaría a utilizar todos los de C++. Que no es absolutamente necesario, y sería una muy mala idea. (Probablemente no la uso todos los de C, ya sea! Creo montón, de punto flotante, setjmp/longjmp, printf, ...)

En un comentario de Adam Haun menciona RAII y la inicialización. OMI RAII tiene más que ver con la deconstrucción, pero su punto es válido: objetos globales se construirá antes de su principal comienza, por lo que podrían trabajar en supuestos no válidos (como una de las principales la velocidad de reloj que va a ser cambiado lateron). Que es una razón más por la que NO utiliza código mundial-inicializa los objetos. (Yo uso un linker script que va a fallar cuando he global de código inicializa los objetos.) OMI tales "objetos" debe ser creado explícitamente y se pasa alrededor. Esto incluye un 'espera' instalación 'objeto' que proporciona un wait() función. En mi configuración esta es "objeto", que establece que la velocidad de reloj del chip.

Hablando de RAII: que es uno más de C++ característica que es muy útil en pequeños sistemas embebidos, aunque no por la razón (la desasignación de memoria) se utilizan más que en largere sistemas (pequeños sistemas embebidos en su mayoría no utilizan desasignación de memoria dinámica). Pensar en un recurso de bloqueo: puede hacer que el recurso bloqueado un objeto contenedor, y restringir el acceso a los recursos a ser posible sólo a través del bloqueo de contenedor. Cuando el contenedor se va fuera de alcance, el recurso está desbloqueado. Esto impide el acceso sin bloqueo, y hace que sea mucho más probable que olvidemos el desbloqueo. con algunos (plantilla) la magia puede ser cero sobrecarga.


Si realmente debe ser C....

Usted podría utilizar la macro engaño: declarar su stucts públicamente, por lo que tienen un tipo y pueden ser asignados a nivel mundial, pero destrozar los nombres de sus componentes, más allá de la usabilidad, a menos que algún macro se define de forma diferente, que es el caso en el módulo .c archivo. Para mayor seguridad se podría utilizar el tiempo de compilación en el destrozarlo.

O tienen una versión pública de su estructura que no tiene nada útil en ella, y tienen la versión privada (con datos útil) sólo en su .c archivo, y afirman que ellos son del mismo tamaño. Un poco de archivo engaño podría automatizar este proceso.


@Lundins comentario sobre el mal (embedded) los programadores:

  • El tipo de programador que describir probablemente iba a hacer un lío en cualquier idioma. Macro (presente en C y C++) son una manera obvia.

  • Utillaje puede ayudar hasta cierto punto. Para mis estudiantes me mandato incorporado un script que especifica sin excepciones, no-rtti, y da un error del vinculador cuando el montón se utiliza o código inicializa variables globales están presentes. Y especifica advertencia=error y permite que casi todas las advertencias.

  • Animo con el uso de plantillas, pero con constexpr y conceptos metaprogramación es menos necesario.

  • "confundido Arduino programadores" me gustaría mucho para reemplazar el Arduino (cableado, replicación de código en las bibliotecas) estilo de programación con C++ moderno, que puede ser easiere, más seguro, y producir más rápido y más pequeño código. Si sólo tuviera el tiempo y el poder....

7voto

Tom Deloford Puntos 508

Creo FreeRTOS (tal vez otro sistema operativo?) hace algo como lo que usted está buscando mediante la definición de 2 versiones diferentes de la estructura.
El 'real', que se usa internamente por el sistema operativo funciones, y un 'falso' que es el mismo tamaño que el 'real', pero no tiene ninguna utilidad a los miembros en el interior (sólo un montón de int dummy1 y similares).
Sólo la 'falsa' struct se expone fuera de el sistema operativo de código, y esto se utiliza para asignar memoria a la electricidad estática de las instancias de la estructura.
Internamente, cuando las funciones en el sistema operativo son llamados, se pasan a la dirección de la externa 'falso' struct como un mango, y esto es encasillado como un puntero a un 'real' struct así que OS pueden hacer las funciones de lo que deben hacer.

4voto

John Bollinger Puntos 136

Hay una opción para combinar estos de alguna manera anónima struct, enlazador en lugar de la asignación del montón y múltiples/cualquier número de instancias?

Seguro que hay. En primer lugar, sin embargo, reconocen que "cualquier número" de casos debe ser fijo, o, al menos, un límite superior establecido, en tiempo de compilación. Este es un requisito previo para las instancias con las que se asignan estáticamente (lo que se está llamando "enlazador de asignación"). Usted puede hacer que el número ajustable sin fuente de modificación de la declaración de una macro que lo especifica.

A continuación, el archivo de origen que contiene el real declaración struct y todas sus funciones asociadas también declara una matriz de instancias con vinculación interna. Proporciona una matriz, con la vinculación externa, de los punteros a las instancias, o bien una función para acceder a los distintos marcadores de índice. La función de variación es un poco más modular:

el módulo.c

#include <module.h>

// 4 instances by default; can be overridden at compile time
#ifndef NUM_MODULE_INSTANCES
#define NUM_MODULE_INSTANCES 4
#endif

struct module {
    int demo;
};

// has internal linkage, so is not directly visible from other files:
static struct module instances[NUM_MODULE_INSTANCES];

// module functions

struct module *module_init(unsigned index) {
    instances[index].demo = 42;
    return &instances[index];
}

Supongo que usted ya está familiarizado con la forma en la cabecera sería entonces declarar la estructura como un tipo incompleta y declarar todas las funciones (escrito en términos de los punteros a ese tipo). Por ejemplo:

el módulo.h

#ifndef MODULE_H
#define MODULE_H

struct module;

struct module *module_init(unsigned index);

// other functions ...

#endif

Ahora struct module es opaco en la traducción de las unidades de distinto module.c,* y usted puede acceder y utilizar el número de casos se define en tiempo de compilación sin ningún tipo de asignación dinámica.


*A menos que se copia su definición, por supuesto. El punto es que module.h no lo hace.

2voto

Paul Puntos 101

Anónimo estructura, de modo que la estructura sólo puede ser alterado por el uso de las funciones de interfaz

En mi opinión, esto es inútil. Puedes poner un comentario allí, pero ningún punto tratando de ocultarlo más.

C nunca va a proporcionar tales alto aislamiento, incluso si no hay ninguna declaración para la estructura, será fácil para sobrescribir accidentalmente se con, por ejemplo, confunde memcpy() o desbordamiento de búfer.

En lugar de ello, acaba de dar a la estructura de un nombre y de confianza a otras personas a escribir buen código. También hará más fácil depurar cuando la estructura tiene un nombre que puede utilizar para referirse a ella.

1voto

Neil Foley Puntos 1313

Puro SW preguntas son las que mejor le preguntó en https://stackoverflow.com.

El concepto con la exposición de una estructura de tipo incompleta a la persona que llama, como la que usted describe, es a menudo llamado "opaco tipo" o "opaco punteros" - anónimo struct significa algo totalmente diferente.

El problema con esto es que la persona que llama no ser capaz de asignar las instancias del objeto, sólo los punteros. En un PC que utilizaría malloc dentro de los objetos "constructor", pero malloc es un no-go en sistemas embebidos.

Entonces, lo que hacen en embedded es proporcionar un bloque de memoria. Usted tiene una cantidad limitada de memoria RAM, por lo que limitar el número de objetos que se pueden crear no es generalmente un problema.

Consulte asignación Estática de opaco tipos de datos de más de en TAN.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X