2012-10-04 23 views
1

Я пытаюсь преобразовать time_t в in64_t, выполнив следующее.Преобразование time_t в int64_t

time_t t = 1349388030; 

У меня есть API.

SomeObj.setValue(const int64_t)   // Sets the value of SomeObj to the passed argument 
SomeObj.getValue(int64_t & value) const // Returns the value 

Затем я выполняю следующее.

SomeObj.setValue(t) 
int64_t tt; 
SomeObj.getValue(tt) 
assert (tt == t)       // Fails where tt = 109726776 

Может ли кто-нибудь помочь в правильной процедуре литья?

EDIT:

это была ошибка в моем коде, как я использовал set_value

+1

Какой код для 'setValue' и' getValue'? –

+0

Я просто передаю refernce to tt, который получает обновление в getValue. setValue - это api, у меня есть, к которому у меня нет доступа. Но я уверен, что он делает правильные вещи. Я думаю, что это мое кастинг, который сломан. –

+0

«Что такое код», @Mark просит вас обновить свой вопрос, включив в него фактический код. – Nemo

ответ

3

Есть 3 случая, когда нужно беспокоиться о литье из одного целого типа в другой:

  1. Вы отлитые из большого целого числа в маленькой. Я достаточно уверен, что sizeof(int64_t) >= sizeof(time_t) так, чтобы это не было проблемой.
  2. Вы присваиваете неподписанный тип подписанному типу, а значение вне диапазона подписанного типа. Снова маловероятно, так как 1349388030 составляет менее 2^31.
  3. Вы вводите тип подписанного типа без знака, а значение отрицательное. Здесь не применяется.

Я не думаю, что проблема в вашем литье.

+2

Я просто добавлю, что есть, досадно, нет действительно независимого от платформы типа, который может принимать все значения 'time_t' (кроме, конечно,' time_t'). Вы можете подумать, что 'uintmax_t' должен позаботиться об этом, и если бы' time_t' гарантированно был целым типом. Но это не так. Это * арифметический тип *, что означает, что он может даже быть 'float' или' double'. –

0

Я не вижу проблемы с вашим кодом. На некоторых платформах time_t уже есть int64_t. Я думаю, ваша проблема в другом месте. Что внутри SomeObj?

1

Я предполагаю, что из-за того, что вы сказали, что SomeObj на самом деле неважно, что это такое, это всего лишь контейнер для хранения, который вам нужно хранить. Я также предполагаю, что в вашем случае использования, любой формат, который вы храните в , не должен быть переносимым, и сохраненные временные интервалы всегда будут использоваться в той же системе, в которой они созданы . Если какое-либо из этих допущений неверно, то литье не является подходящим решением для вашей проблемы (и я обсужу более подходящее решение ниже, повторите обсуждение о localtime()).

Чтобы сохранить значение time_t внутри int64_t переменной, конечно, SizeOf (time_t) должна быть меньше или равна SizeOf (int64_t), так что ваш код должен иметь чек утверждение для этого. Теперь вы не можете просто назначить time_t для int64_t (который будет работать очень хорошо на большинстве, но не на всех системах), потому что если time_t является типом с плавающей запятой, вы, вероятно, будете потерять точность в преобразовании, а когда это преобразованный обратно в time_t, это может быть не одно и то же значение (хотя оно может быть «близко к» правильному значению). Дело в том, что для переносимого кода вы не можете делать какие-либо предположения относительно формата значения time_t. Позвольте мне повторить здесь, хотя приведенный ниже код является портативным, решение не генерирует значения времени, которые сами переносятся; т.е. если вы генерируете значение time_t в одной системе, а ваш SomeObj передает это значение в другую «систему» ​​(даже на том же процессоре, но скомпилированный другим компилятором) для интерпретации в другой системе, другая система может или не может интерпретировать значение одинаково.Для этого вам необходимо преобразовать time_t в дискретные числа, возможно, через localtime() или localtime_r(), передавать что структуры к другой системе, и преобразовать его в , что формата time_t систем через mktime().

В любом случае, чтобы ввести значение time_t в uint64_t в агностическом режиме интерпретации, вы захотите прочитать биты из местоположения значения time_t как uint64_t. Если time_t не такой широкий, как uint64_t, вы будете читать лишние биты, но это не имеет значения; эти биты являются «неважными» битами. Затем, чтобы прочитать значение time_t из этого uint64_t, вы захотите прочитать биты из местоположения uint64_t как time_t. Другими словами, вы берете адрес исходной переменной , бросаете ее как указатель типа назначения и затем разыскиваете ее. Если размеры типов не совпадают, вы либо прочитаете лишние биты мусора в целевой переменной, либо вы потеряете биты, которые, предположительно, были бы мусорными битами. Вот как вы это делаете в коде ...

#include <time.h> 
#include <assert.h> 

struct SomeClass 
{ 
    int64_t i64; 
    void setValue(const int64_t v) { i64 = v; } 
    void getValue(int64_t& v) const { v = i64; } 
}; 

#if 0 // Set to 1 for C style casting, or 0 for C++ style casting. 

    int main() 
    { 
     assert (sizeof(int64_t) >= sizeof(time_t)); 
     // ...fundamental, otherwise nothing else has any hope of working 

     SomeClass SomeObj; 

     time_t t = 1349388030; 
     int64_t i = *((int64_t*)&t); 
     SomeObj.setValue(i); 

     int64_t ii; 
     time_t tt; 
     SomeObj.getValue(ii); 
     tt = *((time_t*)&ii); 

     assert (tt == t); 
    } 

#else 

    int main() 
    { 
     assert (sizeof(int64_t) >= sizeof(time_t)); 
     // ...fundamental, otherwise nothing else has any hope of working 

     SomeClass SomeObj; 

     time_t t = 1349388030; 
     int64_t i = *reinterpret_cast<int64_t*>(&t); 
     SomeObj.setValue(i); 

     int64_t ii; 
     time_t tt; 
     SomeObj.getValue(ii); 
     tt = *reinterpret_cast<time_t*>(&ii); 

     assert (tt == t); 
    } 

#endif 
Смежные вопросы