Search code examples
cmacrosc-header

Macros defined in time.h not recognized


Originally, I wanted to cast a struct timeval to a timespec one.

At first, it did not seem difficult, as a solution is proposed there: Is there a standard way to convert a struct timeval into a struct timespec?

A macro, TIMEVAL_TO_TIMESPEC is supposed to do the job.

As indicated in the docs (https://www.daemon-systems.org/man/TIMEVAL_TO_TIMESPEC.3.html) it only asks for sys/time.h to be included. But I still get the same answer when I try to compile:`warning: implicit declaration of function ‘TIMEVAL_TO_TIMESPEC’ [-Wimplicit-function-declaration]

I even tried to compile the example given in the docs:

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

static void example(struct timespec *spec, time_t minutes) {
    struct timeval elapsed;

    (void)gettimeofday(&elapsed, NULL);

    _DIAGASSERT(spec != NULL);
    TIMEVAL_TO_TIMESPEC(&elapsed, spec);

    /* Add the offset for timeout in minutes. */
    spec->tv_sec = spec->tv_sec + minutes * 60;
}

int main(){
    return 0;
}

When compiling I get:

test.c: In function ‘example’:
test.c:10:2: warning: implicit declaration of function ‘_DIAGASSERT’ [-Wimplicit-function-declaration]
  _DIAGASSERT(spec != NULL);
  ^
test.c:11:2: warning: implicit declaration of function ‘TIMEVAL_TO_TIMESPEC’ [-Wimplicit-function-declaration]
  TIMEVAL_TO_TIMESPEC(&elapsed, spec);
  ^
/tmp/ccqWnL9I.o: In function `example':
test.c:(.text+0x43): undefined reference to `_DIAGASSERT'
test.c:(.text+0x5b): undefined reference to `TIMEVAL_TO_TIMESPEC'
collect2: error: ld returned 1 exit status

What did I do that was wrong ?


Solution

  • You linked to a NetBSD man page. There is no guarantee that what you read there will have anything to do with Linux or any other OS. On what OS are you developing?

    It looks like the macros are standard in glibc, which is the C library you're using on just about any Linux system. However, if you inspect the sys/time.h file, you'll see that the macros are gated by an #ifdef:

    #ifdef __USE_GNU
    /* Macros for converting between `struct timeval' and `struct timespec'.  */
    # define TIMEVAL_TO_TIMESPEC(tv, ts) {                                   \
            (ts)->tv_sec = (tv)->tv_sec;                                    \
            (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
    }
    # define TIMESPEC_TO_TIMEVAL(tv, ts) {                                   \
            (tv)->tv_sec = (ts)->tv_sec;                                    \
            (tv)->tv_usec = (ts)->tv_nsec / 1000;                           \
    }
    #endif
    

    So you would need to #define __USE_GNU before including sys/time.h in order to expose these macros. As @alk points out in the comments, you get this and more by defining _GNU_SOURCE. You can read more about that here.