2010-06-15 4 views
2

Voici ma situation actuelle:Deux struct tm séparées miroir les uns des autres

  • J'ai deux struct tm, les deux mis à l'heure actuelle
  • Je fais un changement à l'heure dans l'un des struct
  • Le changement se produit dans l'autre structure magiquement ....
  • Comment puis-je empêcher cela de se produire? Je dois être capable de comparer et de connaître le nombre de secondes entre deux moments différents - l'heure actuelle et l'heure à venir. J'ai utilisé difftime et mktime pour le déterminer. Je reconnais que techniquement je n'ai pas besoin de deux structures (l'autre structure pourrait juste être un temps chargé avec du temps brut) mais je suis toujours intéressé à comprendre pourquoi cela se produit.

vide Tracker :: moniteur (char * buffer) {

// time handling 
time_t systemtime, scheduletime, currenttime; 
struct tm * dispatchtime; 
struct tm * uiuctime; 
double remainingtime; 


// let's get two structs operating with current time 
dispatchtime = dispatchtime_tm(); 
uiuctime = uiuctime_tm(); 

// set the scheduled parameters 
dispatchtime->tm_hour = 5; 
dispatchtime->tm_min = 05; 
dispatchtime->tm_sec = 14; 

uiuctime->tm_hour = 0; 

    // both of these will now print the same time! (0:05:14) 
    // what's linking them?? 

// print the scheduled time 
printf ("Current Time : %2d:%02d:%02d\n", uiuctime->tm_hour, uiuctime->tm_min, uiuctime->tm_sec); 
printf ("Scheduled Time : %2d:%02d:%02d\n", dispatchtime->tm_hour, dispatchtime->tm_min, dispatchtime->tm_sec); 

}

struct tm* Tracker::uiuctime_tm(){ 
    time_t uiucTime; 
    struct tm *ts_uiuc; 

    // give currentTime the current time 
    time(&uiucTime); 

    // change the time zone to UIUC 
    putenv("TZ=CST6CDT"); 
    tzset(); 

    // get the localtime for the tz selected 
    ts_uiuc = localtime(&uiucTime); 

    // set back the current timezone 
    unsetenv("TZ"); 
    tzset(); 

    // set back our results 
    return ts_uiuc; 
} 

struct tm* Tracker::dispatchtime_tm(){ 
    time_t currentTime; 
    struct tm *ts_dispatch; 

    // give currentTime the current time 
    time(&currentTime); 

    // get the localtime for the tz selected 
    ts_dispatch = localtime(&currentTime); 

    // set back our results 
    return ts_dispatch; 
} 

Répondre

3

Vous devez faire ceci:

struct tm* temp_tm; 
struct tm dispatchtime; // No longer a pointer 
struct tm uiuctime;  // No longer a pointer 

temp_tm = dispatchtime_tm(); 
dispatchtime = *temp_tm; // Member to member copy 

temp_tm = uiuctime_tm(); 
uiuctime = *temp_tm; // Member to member copy 

De cette façon, vous garderez une copie locale du tm struct. Cette structure est allouée en interne dans la bibliothèque standard, chaque appel à localtime pointera vers la même adresse mémoire!

+0

Votre solution aurait pu être encore plus simple.Je ne sais pas pourquoi vous avez affecté d'abord à un temp_tm, puis au tm final, les travaux suivants également: dispatchtime = * dispatchtime_tm(); uiuctime = * uiuctime_tm(); – BSchlinker

+0

Vous avez raison. Mon échantillon utilise une étape intermédiaire juste pour être aussi compréhensible et lisible que possible. – Wizard79

+0

Compris. J'apprécie la clarté, j'étais juste abasourdi pendant un moment après que j'ai regardé votre solution quant à la raison pour laquelle vous avez inclus cette étape. – BSchlinker

3

http://www.cplusplus.com/reference/clibrary/ctime/localtime/

Cette structure est allouée de manière statique et partagée par les fonctions gmtime et localtime. Chaque fois que l'une de ces fonctions est appelée, le contenu de cette structure est écrasé.

Vous devrez copier la valeur hors de la structure. Vos fonctions pourraient retourner une struct tm en valeur, vous pourriez déréférencer les fonctions du programme principal, etc.

+0

Mais localtime est appelé en premier, puis la structure est modifiée. Je ne vois pas la pertinence de ce que vous avez cité. – BSchlinker

+0

@BSchlinker La structure est renvoyée et stockée par pointeur, mais les deux pointeurs différents pointent tous les deux sur la même mémoire statique. –

+0

À l'intérieur de 'uiuctime_tm' et' dispatchtime_tm', vous renvoyez simplement le pointeur donné en appelant 'localtime'. Dans votre programme principal, vous stockez le même pointeur. Ce pointeur pointera toujours vers la même structure. En appelant 'uiuctime_tm' après' dispatchtime_tm', vous écrasez la structure. Vous devez copier les données hors de la structure puisque tous vos pointeurs pointent toujours vers les mêmes données. – Cogwheel

1

Vous n'avez actuellement pas deux structures tm différentes. Ce que vous avez est deux pointeurs de struct tm, pointant tous deux sur la même structure statique retournée par localtime. Il semble donc que les changements à l'un affectent l'autre, mais en réalité c'est simplement une structure qui a deux pointeurs différents. La manière la plus sûre de résoudre ceci est de ne pas s'appuyer sur la structure statique de localtime, mais d'utiliser localtime_r qui nécessite que vous passiez votre propre pointeur de structure tm, qui sera ensuite rempli. Par exemple:

void Tracker::uiuctime_tm(struct tm* out){ 
    time_t uiucTime; 

    // give currentTime the current time 
    time(&uiucTime); 

    // change the time zone to UIUC 
    putenv("TZ=CST6CDT"); 
    tzset(); 

    // get the localtime for the tz selected, and set back the result into the output parameter. 
    localtime_r(&uiucTime, out); 

    // set back the current timezone 
    unsetenv("TZ"); 
    tzset(); 
} 

struct tm uiuctime; 
uiuctime_tm(&uiuctime); 
+0

J'apprécie votre explication de localtime_r. Il n'était pas listé sur cplusplus.com donc je ne le savais pas. – BSchlinker

Questions connexes