uso teclado raya para niƱos largo guion ejemplos ejemplo dialogo corto c++ arduino int unsigned signed

c++ - teclado - uso del guion corto



Interpretar un int sin signo(largo) como firmado en C++ (3)

Desea utilizar static_cast , algo así como:

static_cast<signed long>(your_unsigned_long)

En Arduino C ++:

Quiero reinterpretar los 32 bits de un largo sin signo como un largo firmado. Los mismos bits exactos, solo se consideran como un entero complementario de 2 en lugar de como un entero sin signo. No creo que simplemente lanzarlo (a largo) hará el truco. ¿Me equivoco?

O tal vez hay una mejor manera. Estoy usando un tiempo sin firmar como temporizador. Ocasionalmente leo su valor actual y lo comparo con una lectura anterior (ambos largos sin firmar) para ver cuánto tiempo ha pasado. Necesito manejar un posible desbordamiento, lo que causaría que el valor actual sea MENOR que el valor anterior. Interpretar ambos valores como largos firmados y restar parece dar la respuesta correcta.

Intenté esto:

return reinterpret_cast<long>(time4) - reinterpret_cast<long>(currTimeLo); // treat unsigned as 2''s complement

pero acaba de obtener un error de compilación:

Arduino: 1.6.7 (Mac OS X), placa: "Arduino Nano, ATmega328" conversión no válida del tipo ''long unsigned int'' para escribir ''long int''


En cuanto al problema más profundo / original de comprobar cuánto tiempo ha pasado comparando dos contadores sin firmar, donde podría haber habido 1 único envolvente:

simplemente reste el más antiguo del último usando aritmética sin signo.

Suponiendo que currTimeLo es un valor de contador para la hora actual, y time4 es un valor anterior, y ambos son de tipo sin firmar (o el de tipo con signo promueve el tipo sin signo del otro),

return currTimeLo - time4;

Esto se debe a que C ++ garantiza que la aritmética sin signo se realiza módulo 2 n , donde n es el número de bits en la representación del valor del tipo sin signo.

En el caso en el que haya habido más de 1 envolvimiento, este enfoque no funcionará. En ese caso, necesita usar tipos con mayor rango numérico.

Con respecto al problema del título de la pregunta de interpretar un valor sin signo como un valor firmado del complemento de 2:

Primero ten en cuenta que no es necesario. Es la Y en un problema X / Y. Obtener la diferencia entre dos contadores, donde lo último podría haberse ajustado, es la X original, y tiene una solución trivial (arriba).

Pero luego, ya que es lo que se pregunta en el título:

Hasta donde yo sé, todas las implementaciones de C ++ existentes son para arquitecturas donde los enteros con signo utilizan la representación del complemento de 2.

El Holy Standard ™ deja que la implementación defina el resultado de la conversión a un tipo entero con signo cuando el valor original no puede representarse en ese tipo. Cualquier implementación razonable de C ++ simplemente te permitirá hacerlo a través de static_cast . Por lo tanto,

return static_cast<long>(time4) - static_cast<long>(currTimeLo);

Pero no hay garantía de que su compilador en Arduino sea razonable con respecto a este asunto.

Deberá verificarlo y utilizar las opciones relevantes si es necesario, suponiendo que el comportamiento se puede ajustar si no es razonable por defecto.

Las soluciones incluyen

  • lanzando punteros o referencias a través de reinterpret_cast ,

  • copiar bytes vía eg memcpy , formalmente seguro pero complejo e innecesariamente potencialmente ineficiente,

  • utilizando un acceso formal de miembro de la Unión UB, o

  • seguro pero complejo, dividiendo el valor y recombinándolo.

El último punto se puede hacer de una manera casi elegante que alguien publicó en respuesta a la variante de abogado de idioma de esta pregunta anteriormente en SO. Lamentablemente, no recuerdo ese truco, solo que me impresionó por ser tan obvio y sin embargo uno en el que no pensé. Pero recomiendo el simple static_cast , debidamente probado.


En el complemento a 2, simplemente el valor del molde funciona, porque ajusta el valor del módulo 2 ^ n, es decir, trata el mismo patrón de bits que el otro tipo. Por ejemplo (long)0xFFFFFFFFu devuelve -1

Sin embargo, la cuestión es que tanto la suma como la resta producen 1 bit carry / borrow más . Se debe almacenar un bit más en algún lugar junto con los 32 bits bajos. Por lo tanto, el simple hecho de asignar los valores para signed y restar no funciona, aunque parece funcionar para valores que no están muy lejos el uno del otro. Pruebe LONG_MAX - LONG_MIN o LONG_MIN - LONG_MAX para ver cómo el resultado no se puede almacenar por long incluso cuando ambos operandos son long .

Para superar esto, las únicas maneras son usar un tipo más amplio

return static_cast<long long>(time4) - static_cast<long long>(currTimeLo);

o manejar la aritmética int grande manualmente

if (time4 > rcurrTimeLo) // time hasn''t overflowed { timediff = time4 - rcurrTimeLo; // do something, for example set overflow flag: OV = 0; } else { timediff = rcurrTimeLo - time4; // do something, for example set overflow flag: OV = 1; }

Si lo usa en una función, debe devolver tanto el acarreo de desbordamiento como la diferencia baja de 32 bits, por lo que la primera solución parece ser más fácil en una computadora de 32 o 64 bits, y la segunda será más rápida en un 8- bit MCU como ATmega

Si puede garantizar que los 2 operandos nunca son más que LONG_MAX lejos el uno del otro, un simple static_cast a long funcionará

return static_cast<long>(time4) - static_cast<long>(currTimeLo);