Problem z działaniami na long longach [C++ Builder]

Witam.

Robię w C++ Builderze program zliczający czas, jaki spędzam na komputerze.

Wszystko działało, jednak zauważyłem, że liczba sekund była zbyt duża dla inta.

Dałem więc tę zmienną jaką long long, jednak kompilator pokazuje błąd.

Myślałem, że to problem z różnymi typami zmiennych, ale zamieniłem odpowiednie zmienne na long longi i dalej nie działa.

Błąd brzmi " [C++ Error] Unit1.cpp(37): E2015 Ambiguity between ‘_fastcall System::operator -(double,const System::Variant &)’ and ‘_fastcall System::operator -(int,const System::Variant &)’ "

Tutaj jest Unit1.cpp:

 

//---------------------------------------------------------------------------
 
#include <vcl.h>
#include <stdio.h>
#pragma hdrstop
 
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "trayicon"
#pragma resource "*.dfm"
Tokno *okno;
 
long long sekd;
FILE * plik;
 
//---------------------------------------------------------------------------
__fastcall Tokno::Tokno(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall Tokno::Timer1Timer(TObject *Sender)
{
        plik = fopen("C:\\Users\\GOKOP\\Documents\\NoLifeCounter\\sek_komp", "r");
        fscanf(plik, "%u", &sekd);
 
        long long s, m, h;
        AnsiString sek, min, godz;
 
        h = sekd / 3600;
        godz = IntToStr(h);
 
        m = (sekd - h * 3600) / 60;
        min = IntToStr(m);
 
        s = sekd - h*3600 - min*60;
        sek = IntToStr(s);
 
        licznik -> Caption = godz+"h "+min+"min "+sek+"s";
 
        sekd++;
 
        freopen("C:\\Users\\GOKOP\\Documents\\NoLifeCounter\\sek_komp", "w", plik);
        fprintf(plik, "%u", sekd);
        fclose(plik);
}
//---------------------------------------------------------------------------
void __fastcall Tokno::FormClose(TObject *Sender, TCloseAction &Action)
{
        Action = caNone;
        okno -> Hide();
}
//---------------------------------------------------------------------------
 
void __fastcall Tokno::TrayIcon1Click(TObject *Sender)
{
        okno -> Show();
        Application->BringToFront();
}
//---------------------------------------------------------------------------

Bajki opowiadasz. Int mieści 2^31 - 1 czyli 2147483647 sekund. Jeśli podzielimy to przez 3600 otrzymamy godziny: 596523.235278 godzin, jeśli to z kolei podzielisz przez 24, to otrzymasz liczbę dni: 24855.1348032, a to po podzieleniu przez 365 da ci liczbę lat, czyli: 68.0962597349. Chcesz powiedzieć, że spędziłeś na komputerze ponad 68 lat?

No, nie…

Tylko że licznik cały czas działał i nagle się wyzerował. Jak to wytłumaczysz?

Przy jakiej wartości ci się wyzerował?

Około 11-12 godzin. Dokładnej ilości sekund nie pamiętam.

Dodam jeszcze, że wtedy zawiesił mi się komputer, ale nie powinno mieć to znaczenia, bo program zapisuje przecież wartość co sekundę…

Co rozumiesz przez zawiesił? Resetowałeś go?

Poza tym ma to znaczenie, program nie wykonuje się transakcyjnie, więc jeśli zostanie wyłączony w momencie, kiedy wykona instrukcję:

freopen("C:\\Users\\GOKOP\\Documents\\NoLifeCounter\\sek_komp", "w", plik);

kiedy to ustawi plik do zapisu wymazując poprzedni kontent, ale wyłączony zostanie przed wykonaniem

fclose(plik);

to nic się nie zapisze.

Dlatego z reguły do przechowywania używa się baz danych, albo możesz zaimplementować własne przywracanie danych w obliczu odcięcia zasilania, tak jak robi to np. Subversion czy git.

A wyjaśniłbyś mniej więcej, jak działa to przywracanie?

W najprostszym podejściu:

Zamiast od razu nadpisywać stare dane nowymi (właściwie to nawet nie nadpisujesz, tylko kasujesz stare a dopiero potem piszesz nowe), zapisuj nowe dane do drugiego pliku.

Po zamknięciu drugiego pliku, usuń pierwszy plik (ten ze starymi danymi) i zmień nazwę drugiego pliku na taką jaką miał oryginalny plik.

W zależności od czasu wystąpienia awarii, po ponownym uruchomieniu masz jedną z sytuacji:

  1. jest tylko plik o pierwszej nazwie – wszystko w porządku.

  2. są oba pliki – nie wiesz w jakim stanie jest drugi plik, więc go usuwasz, zostawiasz tylko pierwszy (masz może nie najnowsze dane, ale na pewno poprawne).

  3. jest tylko plik o drugiej nazwie – ponieważ pierwszy usunąłeś dopiero po zamknięciu drugiego, więc wiesz, że drugi jest poprawny, zmieniasz jego nazwę na pierwszą.