¿Cuándo debo utilizar la abstracción de tipos en sistemas integrados?

StackOverflow https://stackoverflow.com/questions/7084

  •  08-06-2019
  •  | 
  •  

Pregunta

He trabajado en varios sistemas integrados diferentes.Todos han usado typedefs (o #defines) para tipos como UINT32.

Esta es una buena técnica, ya que le indica al programador el tamaño del tipo y lo hace más consciente de las posibilidades de desbordamiento, etc.

Pero en algunos sistemas sabes que el compilador y el procesador no cambiarán durante la vida del proyecto.

Entonces, ¿qué debería influir en su decisión de crear y aplicar tipos de proyectos específicos?

Editar Creo que logré perder la esencia de mi pregunta, y tal vez realmente son dos.

Con la programación integrada, es posible que necesite tipos de tamaño específico para las interfaces y también para hacer frente a recursos restringidos como la RAM.Esto no se puede evitar, pero puedes optar por utilizar los tipos básicos del compilador.

Para todo lo demás los tipos tienen menos importancia.
Debe tener cuidado de no provocar un desbordamiento y es posible que deba tener cuidado con el uso del registro y la pila.Lo que puede llevarte a UINT16, UCHAR.Utilizando tipos como UCHAR Sin embargo, puede agregar "pelusa" del compilador.Debido a que los registros suelen ser más grandes, algunos compiladores pueden agregar código para forzar el resultado en el tipo.

i++;
puede llegar a ser
ADD REG,1
AND REG, 0xFF
lo cual es innecesario.

Entonces creo que mi pregunta debería haber sido:-

Dadas las limitaciones del software integrado, ¿cuál es la mejor política a establecer para un proyecto en el que habrá muchas personas trabajando en él, no todas las cuales tendrán el mismo nivel de experiencia?

¿Fue útil?

Solución

Utilizo la abstracción de tipos muy raramente.Aquí están mis argumentos, ordenados en orden creciente de subjetividad:

  1. Las variables locales son diferentes de los miembros de la estructura y las matrices en el sentido de que desea que quepan en un registro.En un objetivo de 32b/64b, un local int16_t puede hacer que el código sea más lento en comparación con un int local ya que el compilador tendrá que agregar operaciones a /force/ overflow de acuerdo con la semántica de int16_t.Mientras que C99 define una intfast_t typedef, AFAIK, un int simple encajará igual de bien en un registro, y seguro que es un nombre más corto.

  2. Las organizaciones a las que les gustan estos tipos de definición casi invariablemente terminan con varios de ellos (INT32, int32_t, INT32_T, hasta el infinito).Por lo tanto, las organizaciones que utilizan tipos integrados están en mejor situación, en cierto modo, al tener un solo conjunto de nombres.Desearía que la gente usara los typedefs de stdint.h o windows.h o cualquier cosa existente;y cuando un objetivo no tiene ese archivo .h, ¿qué tan difícil es agregar uno?

  3. En teoría, los typedefs pueden ayudar a la portabilidad, pero yo, por mi parte, nunca obtuve nada de ellos.¿Existe algún sistema útil que pueda migrar de un objetivo de 32b a uno de 16b?¿Existe un sistema 16b que no sea trivial de trasladar a un objetivo 32b?Además, si la mayoría de las variables son enteras, en realidad obtendrás algo de los 32 bits en el nuevo objetivo, pero si son int16_t, no lo harás.Y los lugares que son difíciles de transportar tienden a requerir inspección manual de todos modos;Antes de probar un puerto, no sabes dónde están.Ahora, si alguien piensa que es tan fácil portar cosas si tiene typedefs por todas partes, cuando llegue el momento de portar, lo que sucede en pocos sistemas, escriba un script que convierta todos los nombres en el código base.Esto debería funcionar según la lógica de "no se requiere inspección manual" y pospone el esfuerzo hasta el momento en el que realmente genera beneficios.

  4. Ahora bien, si la portabilidad puede ser un beneficio teórico de los typedefs, legibilidad Seguro que se va por el desagüe.Basta con mirar stdint.h: {int,uint}{max,fast,least}{8,16,32,64}_t.Muchos tipos.Un programa tiene muchas variables;¿Es realmente tan fácil de entender cuáles deben ser? int_fast16_t y cuales deben ser uint_least32_t?¿Cuántas veces estamos cambiando silenciosamente entre ellos, haciéndolos completamente inútiles?(Me gustan especialmente las conversiones BOOL/Bool/eBool/boolean/bool/int.Cada programa escrito por una organización ordenada que exige typedefs está plagado de eso).

  5. Por supuesto, en C++ podríamos hacer que el sistema de tipos sea más estricto, envolviendo números en instancias de clase de plantilla con operadores sobrecargados y demás.Esto significa que ahora recibirá mensajes de error del tipo "la clase Número<int,Least,32> no tiene operador+ sobrecarga para el argumento de tipo clase Número<unsigned long long,Fast,64>, los candidatos son..." I Tampoco llames a esto "legibilidad".Sus posibilidades de implementar estas clases contenedoras correctamente son microscópicas y la mayoría de las veces esperará a que se compilen las innumerables instancias de plantilla.

Otros consejos

El estándar C99 tiene varios tipos de enteros de tamaño estándar.Si puede utilizar un compilador que admita C99 (gcc lo hace), los encontrará en <stdint.h> y puedes usarlos en tus proyectos.

Además, puede ser especialmente importante en proyectos integrados utilizar tipos como una especie de "red de seguridad" para cosas como conversiones de unidades.Si puede usar C++, entiendo que existen algunas bibliotecas de "unidades" que le permiten trabajar en unidades físicas definidas por el sistema de tipos de C++ (a través de plantillas) que se compilan como operaciones en los tipos escalares subyacentes.Por ejemplo, estas bibliotecas no le permitirán agregar un distance_t a un mass_t porque las unidades no se alinean;De hecho, obtendrás un error de compilación.

Incluso si no puedes trabajar en C++ u otro lenguaje que te permita escribir código de esa manera, al menos puedes usar el sistema de tipo C para ayudarte a detectar errores como ese a simple vista.(Ésa era en realidad la intención original de la notación húngara de Simonyi). Sólo porque el compilador no le gritará por agregar una meter_t a un gram_t no significa que no debas usar tipos como ese.Entonces las revisiones de código serán mucho más productivas a la hora de descubrir errores unitarios.

Mi opinión es si dependes de un tamaño mínimo/máximo/específico no simplemente asuma que (digamos) un unsigned int es de 32 bytes - uso uint32_t en su lugar (suponiendo que su compilador admita C99).

Me gusta usar los tipos stdint.h para definir las API del sistema específicamente porque dicen explícitamente qué tan grandes son los elementos.En los viejos tiempos de Palm OS, las API del sistema se definían utilizando un montón de tipos indecisos como "Word" y "SWord" que se heredaron de Mac OS muy clásico.Hicieron una limpieza para decir Int16 e hizo que la API fuera más fácil de entender para los recién llegados, especialmente con los extraños problemas del puntero de 16 bits en ese sistema.Cuando estaban diseñando Palm OS Cobalt, cambiaron esos nombres nuevamente para que coincidieran con los nombres de stdint.h, haciéndolo aún más claro y reduciendo la cantidad de definiciones de tipos que tenían que administrar.

Creo que los estándares MISRA sugieren (¿exigen?) el uso de typedefs.

Desde una perspectiva personal, el uso de typedefs no deja confusión en cuanto al tamaño (en bits/bytes) de ciertos tipos.He visto a desarrolladores líderes intentar ambas formas de desarrollo utilizando tipos estándar, p.int y usar tipos personalizados, p.UINT32.

Si el código no es portátil hay poco real beneficio al usar typedefs, sin embargo Si, como yo, trabajas con ambos tipos de software (entorno portátil y fijo), puede resultar útil mantener un estándar y utilizar los tipos personalizados.Al menos, como usted dice, el programador es muy consciente de cuánta memoria está utilizando.Otro factor a considerar es ¿qué tan "seguro" está de que el código no se trasladará a otro entorno?He visto que el código específico del procesador debe traducirse porque un ingeniero de hardware de repente tuvo que cambiar una placa. Esta no es una situación agradable, pero debido a los tipos de definición personalizados, podría haber sido mucho peor.

Consistencia, conveniencia y legibilidad."UINT32" es mucho más legible y grabable que "unsigned long long", que es el equivalente para algunos sistemas.

Además, el compilador y el procesador pueden estar fijos durante la vida de un proyecto, pero el código de ese proyecto puede encontrar nueva vida en otro proyecto.En este caso, es muy conveniente tener tipos de datos consistentes.

Si sus sistemas integrados son de alguna manera un sistema crítico de seguridad (o similar), es fuertemente aconsejado (si no es necesario) para usar typedefs sobre tipos simples.

Como conocimientos tradicionales. ha dicho antes, MISRA-C tiene una regla (consultiva) para hacerlo:

Regla 6.3 (consejo): Se deben utilizar typedefs que indiquen el tamaño y el signo en lugar de los tipos numéricos básicos.

(de MISRA-C 2004;es la Regla #13 (adv) de MISRA-C 1998)


Lo mismo se aplica también a C++ en esta área;p.ej. Estándares de codificación JSF C++:

Regla AV 209 Se creará un archivo de UniversaltyPes para definir todos los tipos de STA NDARD para que los desarrolladores los usen.Los tipos incluyen:[uint16, int16, uint32_t, etc.]

Usando <stdint.h> hace que su código sea más portátil para pruebas unitarias en una PC.

Puede molestarte bastante cuando tienes pruebas para todo, pero aún así falla en tu sistema de destino porque un int De repente tiene sólo 16 bits de longitud.

Quizás sea raro, pero uso ub, ui, ul, sb, si y sl para mis tipos de números enteros.Quizás la "i" para 16 bits parezca un poco anticuada, pero me gusta más el aspecto de ui/si que de uw/sw.

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