Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Printing time_t as long int without casting gives unexpected behaviour

Tags:

c++

c

datetime

I am trying to print time_t without casting it as long int in Microsoft Visual Studio Project and it is giving me unexpected result. The source code is

#include <time.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <string.h>

int main()
{
    int a=1,b=2;
    long int c=3;
    time_t myTime;
    time(&myTime);
    printf("%d_%ld_%d_%ld",a,myTime,b,c);
    printf("\n");
    getchar();
    return 0;
}

The output is 1_1389610399_0_2. This is running fine on my linux machine though.I understand that time_t should not be printed like this but I am not sure why? Please tell me how to debug such problem?

EDIT: I was expecting the output to be 1_1389610399_2_3 given the fact that time_t is considered as arithmetic in C.

like image 311
Abhishek Avatar asked Jan 13 '14 10:01

Abhishek


4 Answers

Who says time_t is a long? It may be any arithmetic type. You must explicitly cast it to some defined type when using printf.

Use ostream, and avoid such problems.

like image 67
James Kanze Avatar answered Nov 02 '22 22:11

James Kanze


I was expecting the output to be 1_1389610399_2_3

You are wrong to expect this. Different types have different sizes, and when you pass the "wrong" type via varargs this means that the receiver can no longer find everything on the stack in the expected locations. That's why behavior is undefined when the formatting codes don't match the arguments: the receiver is not reading the same types that the caller is writing.

The 0 that you see printed out where you expected b, is the most significant 32 bits of the 64-bit long long value that is placed on the stack when you pass a time_t via varargs (in this implementation). The %ld formatting code only took the first 4 bytes of the value of myTime, leaving the rest to be taken by the next formatting code.

When it works on linux, that's because time_t is long on that implementation and so your format code matches the type you pass.

There is a kind of "all-purpose" way to print any signed integer, which is to convert it to intmax_t and use the formatting code %j. Unfortunately you aren't guaranteed that time_t is a signed type, or even that it's an integer type. So this would be more portable but still not strictly so, because the value of myTime in theory might not be in range of intmax_t at all. In C++ you should use std::cout << myTime;, because that avoids you needing to know the actual type aliased by time_t (just as long as it's not any kind of char).

Alternatively you can use difftime to coerce your time to double, which you know how to print. Or you can use gmtime or localtime to get a broken-down calendar time, each component of which you know how to print either with printf or with strftime.

like image 39
Steve Jessop Avatar answered Nov 02 '22 23:11

Steve Jessop


To show its (time_t) contents in a safe manner, you should first use (ie.) gmtime to convert it to struct tm, and then use one of its fields or use strftime to convert it further to string.

like image 35
marcinj Avatar answered Nov 02 '22 23:11

marcinj


In order to print a 64 bit integer using a format string you have to use %I64d rather than %ld. However, be ware because the type of time_t depends on your hardware's bitness.

like image 44
Uri Y Avatar answered Nov 02 '22 22:11

Uri Y