Trying to get time from command line and store it in struct timespec variable

150 views Asked by At

I am trying to input a time in a epoch format from the command line and I want to store it in a struct timespec variable.

I am able to store it and somehow print it but when I add something to the timespec variable it is giving strange things

This is the code

#include <time.h>
#include <stdio.h>
#include <stdlib.h>



int main (int argc, char *argv[]){

    struct timespec InputTime;

    InputTime.tv_sec = (time_t)argv[1]; //(__time_t)
    InputTime.tv_nsec = (long)argv[2]; //(__syscall_slong_t)

    printf("The time before %s,%s\n",
            InputTime.tv_sec,
            InputTime.tv_nsec);

    InputTime.tv_sec += 3;
    InputTime.tv_nsec += 3;

    printf("The time after %s,%s\n",
            InputTime.tv_sec,
            InputTime.tv_nsec);

    return 0;

}

This are the inputs and the outputs

INPUT

./InputTime 1615578864 438734073

OUTPUT


The time before 140733952311809,140733952311820
The time after 140733952311812,140733952311823

I have tried to use other variable types for *argv[] and try to use %s for the output of print but then the time before gives me the right input but the time after gives me something strange here is the example of output when I change %ld to %s. Additionally when i do this the compiler gives some warnings because I am not using the right format

./InputTime 1615578864 438734073
The time before 1615578864,438734073
The time after 5578864,734073

I am using this gcc version

gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1

There are 1 answers

1
David C. Rankin On BEST ANSWER

Continuing from my comment above. Any time you read text input in C (as opposed to binary input from a file), you are reading characters not numeric values. When the user enters a number, it is a string of digits, not a numeric value. It is up to you, the programmer, to perform the conversion from the string of digits to the numeric value using either the strtol() family of functions which provides full error detection, or at minimum, use sscanf() to validate the conversion from a succeed/fail standpoint.

In your case, you can simply use strtoul() to provide the greatest range for input values. You simply convert argv[1] and argv[2] to numeric values using strtoul(). A minimum validation would be, e.g.

    errno = 0;  /* set errno zero before conversion */
    InputTime.tv_sec = strtoul (argv[1], &endptr, 0);   /* convert w/strtoul */
    if (endptr == argv[1] && InputTime.tv_sec == 0) {   /* validate digits converted */
        fputs ("error: no digits converted.\n", stderr);
        return 1;
    }
    else if (errno) {   /* validate no overflow in conversion */
        fputs ("error: overflow in conversion.\n", stderr);
        return 1;
    }

After passing both validations (that digits were converted and that no error occurred during the conversion), you can have confidence that your struct timespec contains valid input (you can also further check that the converted numbers are within an acceptable range before use)

If you put it altogether, you can do something like the following:

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main (int argc, char *argv[]) {

    struct timespec InputTime;
    char *endptr;
    
    if (argc < 3) {
        fputs ("error: insufficient arguments\n"
            "usage: ./progrm seconds nanoseconds\n", stderr);
        return 1;
    }
    
    errno = 0;  /* set errno zero before conversion */
    InputTime.tv_sec = strtoul (argv[1], &endptr, 0);   /* convert w/strtoul */
    if (endptr == argv[1] && InputTime.tv_sec == 0) {   /* validate digits converted */
        fputs ("error: no digits converted.\n", stderr);
        return 1;
    }
    else if (errno) {   /* validate no overflow in conversion */
        fputs ("error: overflow in conversion.\n", stderr);
        return 1;
    }
    
    errno = 0;  /* set errno zero before conversion */
    InputTime.tv_nsec = strtoul (argv[2], &endptr, 0);   /* convert w/strtoul */
    if (endptr == argv[2] && InputTime.tv_nsec == 0) {   /* validate digits converted */
        fputs ("error: no digits converted.\n", stderr);
        return 1;
    }
    else if (errno) {   /* validate no overflow in conversion */
        fputs ("error: overflow in conversion.\n", stderr);
        return 1;
    }

    printf ("The time before %lu,%09lu\n", InputTime.tv_sec, InputTime.tv_nsec);

    InputTime.tv_sec += 3;
    InputTime.tv_nsec += 3;

    printf ("The time after  %lu,%09lu\n", InputTime.tv_sec, InputTime.tv_nsec);
}

(note: the inclusion of the errno.h header)

Example Use/Output

$ ./bin/inputtime_strtol 1615578864 438734073
The time before 1615578864,438734073
The time after  1615578867,438734076

Look things over and let me know if you have further questions.