24 votos

Para código incrustado, ¿por qué debo usar el tipo "uint_t" en lugar de "unsigned int"?

Estoy escribiendo una aplicación en c para un STM32F105, utilizando gcc.

En el pasado (con proyectos simples), siempre me he definido las variables como char, int, unsigned int, y así sucesivamente.

Veo que es común el uso de los tipos definidos en stdint.h, como int8_t, uint8_t, uint32_t, etc. Esto es cierto en varias API que estoy usando, y también en el BRAZO CMSIS de la biblioteca de ST.

Creo que entiendo por qué deberíamos hacerlo; para permitir que el compilador para optimizar mejor el espacio de la memoria. Espero que puede haber otras razones.

Sin embargo, debido a de c del entero de las reglas de la promoción, sigo corriendo contra de la conversión de las advertencias en cualquier momento que yo intente agregar dos valores, hacer una operación bit a bit, etc. La advertencia se lee algo como conversion to 'uint16_t' from 'int' may alter its value [-Wconversion]. La cuestión que se discute aquí y aquí.

Esto no sucede cuando se utilizan las variables declaradas como int o unsigned int.

Para dar un par de ejemplos, dado esto:

uint16_t value16;
uint8_t value8;

Tendría que cambiar esto:

value16 <<= 8;
value8 += 2;

a este:

value16 = (uint16_t)(value16 << 8);
value8 = (uint8_t)(value8 + 2);

Es feo, pero puedo hacerlo si es necesario. Aquí están mis preguntas:

  1. Hay un caso donde la conversión de unsigned a firmado y volver a unsigned hará que el resultado incorrecto?

  2. Hay otros grandes razones para/contra el uso de la stdint.h tipos de entero?

Basándose en las respuestas que estoy recibiendo, parece que el stdint.h tipos son generalmente preferidos, aunque c convierte el uint a int y la espalda. Esto lleva a una pregunta más importante:

  1. No puedo evitar las advertencias del compilador mediante el uso de éste (por ejemplo, value16 = (uint16_t)(value16 << 8);). Solo estoy escondiendo el problema? Hay una mejor manera de ir sobre ella?

12voto

Alex Andronov Puntos 178

Las normas conforme compilador donde int tenía entre 17 a 32 bits puede legítimamente hacer todo lo que quiera con el siguiente código:

uint16_t x = 46341;
uint32_t y = x*x; // temp result is signed int, which can't hold 2147488281

Una aplicación que quería hacer, así que legítimamente podría generar un programa que pudiera hacer nada, excepto la salida de la cadena "Fred" repetidamente en cada una de las patillas del puerto de el uso de todo tipo de protocolo. La probabilidad de un programa de obtención portado a una aplicación que no haría tal cosa es excepcionalmente baja, pero es teóricamente posible. Si desea quería escribir el código anterior lo que sería la garantía de que no se involucran en un Comportamiento Indefinido, sería necesario escribir la última expresión como (uint32_t)x*x o 1u*x*x. En un compilador donde int está entre 17 y 31 bits, la última expresión lop de los bits más altos, pero no iba a participar en un Comportamiento Indefinido.

Creo que el gcc advertencias probablemente está tratando de sugerir que el código escrito no es completamente 100% portable. Hay veces cuando el código que realmente debe ser escrito para evitar comportamientos que sería Indefinido en algunas implementaciones, pero en muchos otros casos, simplemente la cifra que el código es poco probable que los utilizados en las implementaciones de que iba a hacer demasiado molesto cosas.

Tenga en cuenta que el uso de tipos como int y short puede eliminar algunos de advertencias y solucionar algunos problemas, pero es probable que crear otros. La interacción entre los tipos como uint16_t y C del entero-las reglas de la promoción son repulsivo, pero estos tipos son probablemente mejor que cualquier otra alternativa.

7voto

afx Puntos 221

Ya #2 de Eugene es probablemente el punto más importante, sólo me gustaría añadir que es un asesor

MISRA (directive 4.6): "typedefs that indicate size and signedness should be used in place of the basic types".

También Jack Ganssle parece ser partidario de que la regla: http://www.ganssle.com/tem/tem265.html

6voto

Dan Auclair Puntos 3063

1) Si usted acaba de lanzar de unsigned a entero con signo de la misma longitud de ida y vuelta, sin ningún tipo de operaciones en el medio, se obtendrá el mismo resultado cada vez, así que no hay problema aquí. Sin embargo, por diversas lógicas y operaciones aritméticas están actuando de manera diferente en signed y unsigned operandos.
2) La principal razón para usar stdint.h tipos es que los bits de tamaño de este tipo se definen los tipos y la igualdad a través de todas las plataformas, lo cual no es cierto para int, long e.t.c., así como char no tiene ningún estándar signess, puede ser con o sin signo por defecto. Hace más fáciles de manipular los datos de conocer el tamaño exacto sin la utilización de cheques y de suposiciones.

3voto

Al pacino Puntos 415

Una manera fácil de eliminar las advertencias es evitar el uso de -Wconversion en el GCC. Creo que tienes que activar esta opción de forma manual, pero si no, usted puede utilizar -Wno-conversión para desactivarlo. Usted puede habilitar advertencias para firmar y FP precisión las conversiones a través de otras opciones, si usted todavía quiere los.

La Wconversion advertencias son casi siempre falsos positivos, que es, probablemente, por qué no, incluso -Wglobals permite por defecto. Un Stack Overflow pregunta tiene un montón de sugerencias para la buena opción de conjuntos. Basado en mi propia experiencia, este es un buen lugar para empezar:

-std=c99 -pedante -Pared -Wglobals -Wshadow

Agregar más si es necesario, pero las probabilidades son que usted no.

Si usted debe mantener -Wconversion, puede acortar su código un poco, sólo por el encasillamiento el número de operando:

value16 <<= (uint16_t)8;
value8 += (uint8_t)2;

Eso no es fácil de leer sin resaltado de sintaxis, aunque.

2voto

en cualquier proyecto de software, es muy importante el uso de portátiles de tipo de definiciones. (incluso la próxima versión de que el mismo compilador necesidades de esta consideración. ) Un buen ejemplo, hace varios años trabajé en un proyecto donde el compilador actual definido 'int' como 8bits. La próxima versión del compilador define 'int' como de 16 bits. Ya que no había usado ningún portátil definiciones de 'int', la ram (de manera efectiva) se duplicó en tamaño y muchas secuencias de código que dependía de un 8bit int error. El uso de un portátil tipo de definición se han evitado que (cientos de horas hombre para solucionar problema.

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