0

I have a structure like below:

typedef struct  ERROR_LOG_EVENT
{
    time_t time;
    uint32_t count;
    int32_t error_type;
} ERROR_LOG_EVENT;

I am storing this structure on a non-volatile memory. On 32-bit system, everything works fine as time_t is 4 bytes(32bit) in width.

But on 64-bit system time_t becomes 8bytes(64bit) wide.

Is there a way to store time in 4byte(32bit) on 64bit system? Can I replace time_t time member of the above structure with something that always is guaranteed to be 32-bit ?

2501
  • 25,460
  • 4
  • 47
  • 87
Monku
  • 2,440
  • 4
  • 33
  • 57
  • I want `4 byte(32bit)` member representing `time` – Monku Mar 07 '17 at 21:17
  • 1
    Yes you can, but only if you don't think your program will be used beyond the year 2106 (if using e.g. `uint32_t`). ***And*** `time_t` is actually an integer counting the number of seconds since 1970-01-01. (If the epoch is earlier then the end date will of course be sooner too.) – Some programmer dude Mar 07 '17 at 21:18
  • 2
    What is the issue with having a 64 bit `time_t`? – NathanOliver Mar 07 '17 at 21:19
  • @Someprogrammerdude I am fine with that assumption. Currently, the project works fine on 32-bit system. We are in a phase to port to 64-bit system, but don't want to increase memory for structures that are stored on non-volatile memory. Precision of time should work fine in both the cases – Monku Mar 07 '17 at 21:20
  • One problem with using `uint32_t` on a system where `time_t` is a 64-bit type, is that you need to explicitly cast assignments to your `time` member variable. Unless you like the compiler giving you warnings about loosing precision or something similar. And there will be some issues if `time_t` is a *signed* 64 bit integer (sign-extension etc). – Some programmer dude Mar 07 '17 at 21:24
  • 1
    If you are into saving memory space, you would need to deal with padding/alignment for your struct with int32 on a 64-bit system. – SegFault Mar 07 '17 at 21:32
  • 1
    @Someprogrammerdude I think the issue is not 2106 but sooner: [2038](https://en.wikipedia.org/wiki/Year_2038_problem) if we go with signed `time_t`. _Only_ 21 years away. – chux - Reinstate Monica Mar 07 '17 at 21:36
  • This discussion provides some nice background on time_t. http://stackoverflow.com/a/471287/6693299 Since time_t is guaranteed to represent the number of ticks since 1970 in either the 32 or 64 bit version, it is safe to take the least significant 32 bits and just store that. It is good to 2038 according to this link, not 2106. – ScottK Mar 07 '17 at 21:37
  • 1
    @chux For a *signed* 32-bit time yes. – Some programmer dude Mar 07 '17 at 21:37
  • 1
    @chux let's assume that he would cast the time_t to an uint32, not int32 – SegFault Mar 07 '17 at 21:38
  • @Someprogrammerdude Agreed with uint32_t, could go to 2106, yet my mis-reading of your comment is an example of the pitfalls of signed _signed_ time. – chux - Reinstate Monica Mar 07 '17 at 21:39
  • 1
    @ScottK "Since time_t is guaranteed to represent the number of ticks since 1970 in either the 32 or 64 bit version" --> That guarantee is not in the C spec. – chux - Reinstate Monica Mar 07 '17 at 21:41
  • 1) You are not allowed to change standard headers. 2) That's an XY problem. **Why** do you want a 32 bit time representation? What is your problem using the correct type? 3) You call for another Y2K problem. Some people learned from it, thus now use a longer type. Why do you want to repeat that nonsense? If you have a storage issue, use a compressed storage format. – too honest for this site Mar 07 '17 at 21:41
  • Does `int32_t error_type;` need 32-bits? – chux - Reinstate Monica Mar 07 '17 at 21:44
  • @chux yes it does. I would like to have 32-bit time representation on 64-bit machine and not changing other members. Since precision is not a problem here, I believe I can go with `uint32_t` – Monku Mar 07 '17 at 21:46
  • 1
    A common hack is to offset the `time_t` based on a more recent epoch, maybe 2107 JAn 1 – chux - Reinstate Monica Mar 07 '17 at 21:47
  • @chux Thanks for the correction. I believe that this guarantee is only for POSIX compliant systems. Is that your understanding? Curious if you know of any popular systems that do not follow this convention regarding time_t representing the number of ticks? – ScottK Mar 07 '17 at 21:47
  • one curious question. if its measurement of clock since 1970, why is it signed data type then ? in what case would we be requiring negative values ? – Monku Mar 07 '17 at 21:49
  • @Monku 1) The error return from various time functions is C specified to be `((time_t) -1)` , so there is at least one "negative" value. 2) The origins of `time_t` hearken to a time when `int` was very popular and some signed integer type has become common practice. – chux - Reinstate Monica Mar 07 '17 at 22:12
  • Hmm, on a 64-bit system, might the structure `ERROR_LOG_EVENT` tend to a 64-bit alignment and then the 32-bit savings are moot? – chux - Reinstate Monica Mar 07 '17 at 22:20
  • 1
    @ScottK I have worked on niched implementations that did not use Jan 1, 1970 integer seconds epoch. Still portable code does not need to know the underlying implementation and so I often don't care much either. I find timezones and DST more of a headache. – chux - Reinstate Monica Mar 07 '17 at 22:23
  • @Monku I suggest staying with `typedef struct ERROR_LOG_EVENT { time_t time; uint32_t count; int32_t error_type; } ERROR_LOG_EVENT;` – chux - Reinstate Monica Mar 07 '17 at 22:24
  • @chux I can pack the structure to use 4-byte alignment. – Monku Mar 07 '17 at 23:39

3 Answers3

1

If memory space optimization if your goal (at the expense of slower access, and time limited to 2106), then you should define your struct as packed to suppress padding:

typedef struct __attribute__((__packed__)) ERROR_LOG_EVENT {
    uint32_t time;
    uint32_t count;
    int32_t error_type;
} ERROR_LOG_EVENT;

Then assign it like that: ERROR_LOG_EVENT.time = <time_t> & 0xFFFFFFFF;

SegFault
  • 1,097
  • 1
  • 14
  • 14
  • why do i need `packing` here ? I believe the `stricter alignment` is 4byte for this structure. Correct me if I am wrong – Monku Mar 07 '17 at 21:51
  • 1
    It depends on the compiler you use and the compilation options you use... – SegFault Mar 07 '17 at 21:54
0

Adapt your code to properly handle a 64-bit timestamp. Specifically, write something that looks like

typedef struct  ERROR_LOG_EVENT
{
    int64_t time;
    uint32_t count;
    int32_t error_type;
} ERROR_LOG_EVENT;

And force your 32-bit code to use this code. Don't try to store time intervals using 32-bit integers. That's always going to be a bad idea, and that's before you hit the problem of "oh, the design requirements changed, we actually want to save nanoseconds, not seconds".

Xirema
  • 19,889
  • 4
  • 32
  • 68
-1

Use uint32_t. If these are unix epoch times, this will be sufficient for storing timestamps that are no further than the year 2105.

ikegami
  • 367,544
  • 15
  • 269
  • 518