tipo promoción en C

4 minutos de lectura

tipo promocion en C
Julien REINAULD

Estoy bastante confundido por el siguiente código:

#include <stdio.h>
#include <stdint.h>

int main(int argc, char ** argv)
{
    uint16_t a = 413;
    uint16_t b = 64948;

    fprintf(stdout, "%u\n", (a - b));
    fprintf(stdout, "%u\n", ((uint16_t) (a - b)));

    return 0;
}

Eso devuelve:

$ gcc -Wall test.c -o test
$ ./test
4294902761
1001
$ 

Parece que la expresión (a – b) tiene tipo uint32_t. No entiendo por qué ya que ambos operadores son uint16_t.

¿Puede alguien explicarme esto?

  • Estás declarando ambos como enteros sin signo y luego haciendo una resta que dará como resultado un número negativo. No puede esperar un comportamiento confiable cuando está haciendo un mal uso de los tipos de datos.

    – en eso

    31 de octubre de 2011 a las 14:04

  • En realidad, eso es exactamente lo que necesito hacer.

    –Julián REINAULD

    31 de octubre de 2011 a las 14:11

  • Así que estaba pensando: en realidad, eso es exactamente lo que necesito hacer. a y b representan los valores de un contador de 16 bits en una pieza de hardware. Un contador de 16 bits cuenta de 0 a 65535. Entonces, a y b son uint16_t. Ahora si quiero saber la cantidad de ciclos que pasaron entre 2 marcas de tiempo ayb, solo tengo que hacer la resta. Si el contador pasó de 10 a 100, sé que han pasado 90 ciclos. Si el contador quiere pasar de 65530 a 2, es decir, pasó de 65530 a 65535, luego volvió a 0 y pasó a 2, sé que pasaron 5 + 1 + 2 = 8 ciclos.

    –Julián REINAULD

    31 de octubre de 2011 a las 14:22

  • Honestamente, esto suena como un problema de diseño. Primero, si es posible que pasen más de 65535 ciclos entre un cheque, su diseño es inherentemente defectuoso ya que ni siquiera puede representar ese número con su tipo de datos. Además, necesita saber de alguna manera si el contador ha retrocedido o no de 65535 a 0 (a menos que asuma que si es más pequeño, se ha retrocedido, pero nuevamente está roto si tiene más de 65535 ciclos entre controles). Si puede garantizar que pasen menos de 65535 ciclos entre comprobaciones, simplemente hágalo si b > a ? b – a : (((65335 – a) + b) + 1). Podría ser capaz de optimizar eso también.

    – en eso

    31 de octubre de 2011 a las 14:34


  • b – a es mucho más simple que b > a ? b – a : (((65335 – a) + b) + 1) …

    –Julián REINAULD

    31 de octubre de 2011 a las 14:42

El estándar C explica esto con bastante claridad (§6.5.6 Operadores aditivos):

Si ambos operandos tienen tipo aritmético, las conversiones aritméticas habituales se realizan sobre ellos.

(§6.3.1.8 Conversiones aritméticas habituales):

… los promociones enteras se realizan en ambos operandos.

(§6.3.1.1 Booleanos, caracteres y números enteros):

Si una int puede representar todos los valores del tipo original, el valor se convierte en un int; … Estos se llaman las promociones enteras. Todos los demás tipos no se modifican por las promociones de enteros.

Ya que int puede representar todos los valores de uint16_t en tu plataforma, a y b se convierten en int antes de realizar la resta. El resultado tiene tipo inty se pasa a printf como un int. Ha especificado el %u formateador con un int argumento; estrictamente hablando, esto invoca un comportamiento indefinido, pero en su plataforma el int argumento se interpreta como su representación de complemento a dos, y eso se imprime.

  • Gracias. Esto es bastante claro 🙂 Eventualmente, simplemente volqué mi expresión a uint16_t.

    –Julián REINAULD

    31 de octubre de 2011 a las 14:45


  • @JulienREINAULD: que funciona bien y es la forma prevista de lidiar con esto. =)

    – Esteban Canon

    31 de octubre de 2011 a las 14:47

Si descarta los bits superiores de un número (mediante la conversión explícita a un entero sin signo de 16 bits), obtendrá un resultado más pequeño (dentro del rango de 0 y 2^16-1) que antes de.

tipo promocion en C
relajarse

C promueve los argumentos para unsigned int antes de hacer la resta. Este es un comportamiento estándar.

Véase, por ejemplo, en una expresión de C donde están presentes un int sin signo y un int con signo, ¿qué tipo se promoverá a qué tipo? para detalles.

  • En realidad, los promueve a cualquiera int o unsigned int – si int puede representar todos los valores de uint16_tentonces serán ascendidos a int.

    – café

    31 de octubre de 2011 a las 14:09

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad