Ich habe die folgende Funktion geschrieben, um den aktuellen Zeitstempel (seit 00 Uhr 1. Januar 1900) zu berechnen. Die Ausgabe, die ich bekomme, ist:
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
Grundsätzlich drucke ich den retval (Funktionsrückgabewert) bei jedem Schritt, um die Berechnungen zu überprüfen und zu verifizieren.
Die Berechnung stimmt bis retval 4
(wenn die Stunden des aktuellen Tages in Sekunden umgewandelt werden). Ich denke, es könnte an einem arithmetischen Überlauf liegen, bin mir aber nicht sicher.
Das Problem scheint in dieser Zeile zu passieren:
retval += (d.hr * 60 * 60); printf("retval 5 %"PRIu32"\r", retval);
retval ist uint32_t und d.hr ist 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;
}
20 * 60 * 60 = 72000
Sie müssen die Multiplikation in 32 Bit durchführen, um einen Überlauf zu vermeiden.
retval += (d.hr * 60UL * 60);
(3615235200-3613161600)/(24*60*60) = 24, also ist die Änderung bei 'retval 4' korrekt und kein Überlauf, also ist Ihre Behauptung, dass sie korrekt sind, "bis Sie zu retval 4 kommen", falsch.
retval 5 ergibt jedoch (3615241664-3615235200) = 60*60*20 - 2**16, also gibt es einen Überlauf. Verwenden Sie ein uint32_t auf der rechten Seite von retval += d.hr * uint32_t(60 * 60u)
.
Vor Ihrer Bearbeitung fehlte ein Leerzeichen zwischen "retval 3" und "3613161600" .
Ankit
Ignacio Vazquez-Abrams
int
es sei denn, einer der Operanden überschreibt es, daher dasL
Suffix für das Literal (fürlong
).Ignacio Vazquez-Abrams