Две отдельные структуры tm, отражающие друг друга

Вот моя текущая ситуация:

  • У меня есть две структуры tm, для которых установлено текущее время.
  • Я вношу изменение в час в одной из структур
  • Изменение происходит в другой структуре волшебным образом....
  • Как мне предотвратить это? Мне нужно иметь возможность сравнивать и знать количество секунд между двумя разными временами — текущим временем и временем в будущем. Я использовал difftime и mktime, чтобы определить это. Я понимаю, что технически мне не нужны две структуры tm (другая структура может быть просто time_t, загруженной необработанным временем), но мне все же интересно понять, почему это происходит.

void Tracker::monitor(char* буфер){

// 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;
}

person BSchlinker    schedule 15.06.2010    source источник


Ответы (3)


Вы должны сделать это:

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

Таким образом вы сохраните локальную копию структуры tm. Эта структура размещается внутри стандартной библиотеки, каждый вызов localtime будет указывать на один и тот же адрес памяти!

person lornova    schedule 15.06.2010
comment
Ваше решение могло быть еще проще. Я не уверен, почему вы назначили сначала temp_tm, а затем окончательному tm, также работает следующее: dispatchtime = *dispatchtime_tm(); uiuctime = *uiuctime_tm(); - person BSchlinker; 15.06.2010
comment
Ты прав. В моем примере используется промежуточный шаг, чтобы быть максимально понятным и читабельным. - person lornova; 15.06.2010
comment
Понял. Я ценю ясность, я просто был ошеломлен на мгновение, когда посмотрел на ваше решение относительно того, почему вы включили этот шаг. - person BSchlinker; 16.06.2010

http://www.cplusplus.com/reference/clibrary/ctime/localtime/< /а>

Эта структура статически выделена и совместно используется функциями gmtime и localtime. Каждый раз, когда вызывается одна из этих функций, содержимое этой структуры перезаписывается.

Вам нужно будет скопировать значение из структуры. Ваши функции могут возвращать структуру tm по значению, вы можете разыменовывать функции в основной программе и т.д.

person Cogwheel    schedule 15.06.2010
comment
Но сначала вызывается локальное время, а затем модифицируется структура. Я не вижу смысла в том, что вы цитируете. - person BSchlinker; 15.06.2010
comment
@BSchlinker Структура возвращается и сохраняется по указателю, но два разных указателя указывают на одну и ту же статическую память. - person Mark B; 15.06.2010
comment
Внутри uiuctime_tm и dispatchtime_tm вы просто возвращаете указатель, полученный при вызове localtime. В вашей основной программе вы сохраняете тот же указатель. Этот указатель всегда будет указывать на одну и ту же структуру. Вызывая uiuctime_tm после dispatchtime_tm, вы перезаписываете структуру. Вам нужно скопировать данные из структуры, так как все ваши указатели всегда указывают на одни и те же данные. - person Cogwheel; 15.06.2010

На самом деле у вас вообще нет двух разных структур tm. У вас есть два указателя на структуру tm, оба указывающие на одну и ту же статическую структуру, возвращаемую localtime. Таким образом, кажется, что изменения в одном влияют на другой, но на самом деле это просто одна структура имеет два разных указателя на нее.

Самый безопасный способ решить эту проблему — не полагаться на статическую структуру localtime, а использовать localtime_r, который требует от вас передачи собственного указателя структуры tm, который затем будет заполнен. Например:

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);
person Mark B    schedule 15.06.2010
comment
Я ценю ваше объяснение localtime_r. Его не было в списке на cplusplus.com, поэтому я не знал об этом. - person BSchlinker; 15.06.2010