Desbordamiento aritmético ATmega328

1

He escrito la siguiente función para calcular la marca de tiempo actual (desde 00h 1 de enero de 1900). La salida que obtengo es:

Current Time & Date : 20:5:32 25/7/2014<\r>
2014 7 25 20 5 32<\r>
retval 1 3597523200<\r>
retval 2 3597523200<\r>
retval 3 3613161600<\r>
retval 4 3615235200<\r>
retval 5 3615241664<\r>
retval 6 3615241964<\r>
retval 7 3615241996<\r>
retval 8 3615241996<\r>
Current time timestamp 3615241996

Básicamente, estoy imprimiendo la retval (valor de retorno de la función) en cada paso para verificar y verificar los cálculos.

El cálculo coincide con hasta retval 4 (cuando las horas del día actual se convierten a segundos). Creo que podría deberse a un desbordamiento aritmético, pero no estoy seguro.

El problema parece estar ocurriendo en esta línea:

retval += (d.hr * 60 * 60); printf("retval 5 %"PRIu32"\r", retval);

retval es uint32_t y d.hr es uint16_t

uint32_t DS1307_GET_CURRENT_TIMESTAMP()
{
    uint32_t retval = SECONDS_SINCE_1900_TO_2014;
    ds1307 d;
    DS1307_GET_DATETIME(&d);
    printf("%u %u %u %u %u %u\r", d.yy,d.mm,d.dd,d.hr, d.min, d.sec);
    printf("retval 1 %"PRIu32"\r", retval);
    //process complete years since 2014 to current year
    uint8_t i=0;
    for(i=0; i<(d.yy - 2014); i++)
    {
        if(DS1307_IS_LEAP_YEAR(2014+i)==0) retval += 31622400;
        else retval += 31536000;
    }
        printf("retval 2 %"PRIu32"\r", retval);

    //process complete months from beginning of current year to current date/time
    for(i=1; i<d.mm; i++)
    {
        if((i==1) || (i==3) || (i==5) || (i==7) || (i==8) || (i==10) || (i==12))
        {
            //31 days
            retval += (31 * 86400);
        }
        else if ((i==4) || (i==6) || (i==9) || (i==11))
        {
            //30 days
            retval += (30 * 86400);
        }
        else 
        {
            //i==2==february. check if leap year
            if(DS1307_IS_LEAP_YEAR(d.yy)==0) retval += (29 * 86400);
            else retval += (28 * 86400);
        }
    }
        printf("retval 3 %"PRIu32"\r", retval);

    //process complete days from beginning of month till current date
    retval += ((d.dd-1) * 86400);
    printf("retval 4 %"PRIu32"\r", retval);

    //process hours, min and seconds - CALCULATION DEVIATES HERE.
    retval += (d.hr * 60 * 60); printf("retval 5 %"PRIu32"\r", retval);
    retval += (d.min * 60); printf("retval 6 %"PRIu32"\r", retval);
    retval += d.sec; printf("retval 7 %"PRIu32"\r", retval);

        printf("retval 8 %"PRIu32"\r", retval);

    return retval;
}
    
pregunta Ankit

2 respuestas

2

20 * 60 * 60 = 72000

Es necesario realizar la multiplicación en 32 bits para evitar un desbordamiento.

retval += (d.hr * 60UL * 60);
    
respondido por el Ignacio Vazquez-Abrams
0

(3615235200-3613161600) / (24 * 60 * 60) = 24, por lo que el cambio en 'retval 4' es correcto y no es un desbordamiento, por lo que su afirmación de que son correctas "hasta que llegue al retval 4" es falso.

retval 5 sin embargo da (3615241664-3615235200) = 60 * 60 * 20 - 2 ** 16, por lo que hay un desbordamiento. Use un uint32_t en el lado derecho de retval += d.hr * uint32_t(60 * 60u) .

Antes de editar, faltaba un espacio entre "retval 3" y "3613161600".

    
respondido por el Pete Kirkham

Lea otras preguntas en las etiquetas