Macros defined in time.h not recognized - c

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 ?

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.

Related

error: dereferencing pointer to incomplete type on stub of gettimeofday

Haven't done much c programming and am running into "error: dereferencing pointer to incomplete type".
Attempting to stub out gettimeofday with call to clock_gettime.
Here is code
#include <time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz)
/* This procedure stubs out call to gettimeofday */
{
struct timespec spec;
// initialize result status to invalid
int result = -1;
// if passed in pointer tv is not NULL
if (tv) {
// retrieve time
result = clock_gettime(CLOCK_REALTIME, &spec);
// if time retreived is valid then
if (result == 0){
tv->tv_sec = spec.tv_sec; // seconds
tv->tv_usec = (spec.tv_nsec / 1.0e3); // Convert nanoseconds to microseconds
}
}
return result;
}
I get the "error dereferencing pointer to incomplete type" on assignment
tv->tv_sec = spec.tv_sec; // seconds
If I compile/link in linux target=i686-pc-linux-gnu but no error intarget=powerpc-xcoff-lynxos178 target environment.
I am #include and that has definition timespec
time.h is different for each target. Thank you for taking time to look at this.
Along with the need for #include <sys/time.h> you are probably seeing a conflict with the prototype for the system's gettimeofday() call. On many systems the second parameter is void *.
The issue for this stub of gettimeofday was we were trying to write the stub to work in 3 different environments. Windows, Linux target and powerpc target - each of which seems to have slight variants in OS headers. What we ended up doing was adding a compiler directive to handle linux vs the other environments where we did not have issues. This is ultimately what we went with - I thought we should have avoided the stub and just called clock_gettime but there were reasons why this way was cheaper.
#include <time.h>
#include <sys/time.h>
#ifdef __linux__
int gettimeofday(struct timeval *__restrict __tv, __timezone_ptr_t __tz)
#else
int gettimeofday(struct timeval * __tv, struct timezone* __tz)
#endif

implicit declaration of function ‘gmtime_r’

What do I need to do to make gcc include the declaration of gmtime_r(3) from time.h? Looking at /usr/include/time.h, gmtime_r and localtime_r are inside #ifdef __USE_POSIX.
Do I need to do something to turn __USE_POSIX on, like a command-line option? I'm running with -std=c99 now. I understand that __USE_* macros are not intended to be set directly by user code.
/* Return the `struct tm' representation of *TIMER
in Universal Coordinated Time (aka Greenwich Mean Time). */
extern struct tm *gmtime (const time_t *__timer) __THROW;
/* Return the `struct tm' representation
of *TIMER in the local timezone. */
extern struct tm *localtime (const time_t *__timer) __THROW;
#ifdef __USE_POSIX
/* Return the `struct tm' representation of *TIMER in UTC,
using *TP to store the result. */
extern struct tm *gmtime_r (const time_t *__restrict __timer,
struct tm *__restrict __tp) __THROW;
/* Return the `struct tm' representation of *TIMER in local time,
using *TP to store the result. */
extern struct tm *localtime_r (const time_t *__restrict __timer,
struct tm *__restrict __tp) __THROW;
#endif /* POSIX */
The proper way to do this is:
#define _POSIX_C_SOURCE 200112L
#include <time.h>
This method indicates explicitly the features that a source file requires, making it self-contained. It is also portable to any POSIX system using any compiler. No special compiler flag is needed.
With GCC this code will compile with -std=c89, -std=c99, or any other value. Importantly what -std=gnu?? enables by default might differ depending on version or platform.
See Feature Test Macros for details.
Actually, gmtime_r is not part of the ISO C99 standard, it’s a POSIX extension. To enable that, use std=gnu99 standard.
You can always verify which features are available for which standard on your system by applying technique from this Pixelbeat article:
It can be quite confusing sometimes to know exactly
what is #defined in your program, and this is especially
true for glibc's "feature" macros. These macros are documented
(info libc "feature test macros"), but it's much easier
to see what's defined directly using "cpp -dD" like:
$ echo "#include <features.h>" | cpp -dN | grep "#define __USE_"
#define __USE_ANSI
#define __USE_POSIX
#define __USE_POSIX2
#define __USE_POSIX199309
#define __USE_POSIX199506
#define __USE_MISC
#define __USE_BSD
#define __USE_SVID
$ echo "#include <features.h>" | cpp -dN -std=c99 | grep "#define __USE_"
#define __USE_ANSI
#define __USE_ISOC99
Also to see all the predefined macros one can do:
$ cpp -dM /dev/null
Note also for compiler specific macros you can do:
$ gcc -E -dM - < /dev/null

When is getdate and strptime not included in time.h?

So the function getdate_r seems to be undefined for me; compiling the following doesn't work in either gcc or clang, (the man page program also doesn't work)
#include <time.h>
int main() {
char timeString[] = "2015/01/01 10:30:50";
struct tm res = {0};
int err = getdate_r(timeString, &res);
return err;
}
clang reports the following
test.c:6:12: warning: implicit declaration of function 'getdate_r' is invalid
in C99 [-Wimplicit-function-declaration]
int err = getdate_r(timeString, &res);
^
1 warning generated.
Other functions from time.h such as getdate, strptime also don't work in a similar manner.
Anyone have an explanation on whats going on?
clang version information
Ubuntu clang version 3.6.0-2ubuntu1 (tags/RELEASE_360/final) (based on LLVM 3.6.0)
Target: x86_64-pc-linux-gnu
Thread model: posix
To make getdate_r available you need to:
#define _GNU_SOURCE 1
before including any include files. Doing so will provide declarations for various GNU extensions including getdate_r:
#define _GNU_SOURCE 1
#include <time.h>
int main(void) {
char timeString[] = "2015/01/01 10:30:50";
struct tm res = {0};
int err = getdate_r(timeString, &res);
return err;
}

resolving redefinition of timespec in time.h

I am writing a program which includes both /usr/include/linux/time.h and /usr/include/stdlib.h.
The problem is:
stdlib.h includes /usr/include/time.h, which defines 'struct timespec', and /usr/include/linux/time.h also defines one. This introduces a compilation error of redefinition.
I've examined the definitions of 'struct timespec' in these two header files:
in /usr/include/time.h:
struct timespec
{
__time_t tv_sec; /* Seconds. */
long int tv_nsec; /* Nanoseconds. */
};
in /usr/include/linux/time.h:
struct timespec {
__kernel_time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
It seems that these definitions are indeed equivalent, but I can't prove it.
My question is: is there a robust way to resolve this redefinition?
Links to discussions on this problem are also highly appreciated. Thanks.
One way to resolve the double-definition error is to rename one of these definitions:
#include <time.h>
#define timespec linux_timespec
#include <linux/time.h>
#undef timespec
And then assert at compile time that both definitions have the same layout:
typedef int assert_same_size[sizeof(struct linux_timespec) == sizeof(timespec) ? 1 : -1];
typedef int assert_same_alignment[__alignof(struct linux_timespec) == __alignof(timespec) ? 1 : -1];
typedef int assert_same_tv_sec[offsetof(struct linux_timespec, tv_sec) == offsetof(struct timespec, tv_sec) ? 1 : -1];
typedef int assert_same_tv_nsec[offsetof(struct linux_timespec, tv_nsec) == offsetof(struct timespec, tv_nsec) ? 1 : -1];
I got the same error in Ecliepse Neon IDE and i resolved it by adding -DHAVE_STRUCT_TIMESPEC in C/C++ Build -> Settings -> GCC C++ Compiler -> Miscellaneous -> Others flag

Why does G_DEFINE_INTERFACE trigger an "expected declaration specifiers" compiler error?

As part of getting familiar with GObject I'm trying to create a "Hello, world" interface following the example in the reference manual. Here's what I have in hello_world_if.h:
#ifndef __HELLO_WORLD_IF_H__
#define __HELLO_WORLD_IF_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define TYPE_HELLO_WORLD_IF (hello_world_if_get_type())
#define HELLO_WORLD_IF(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_HELLO_WORLD_IF, HelloWorldIf))
#define IS_HELLO_WORLD_IF(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_HELLO_WORLD_IF))
#define HELLO_WORLD_IF_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), TYPE_HELLO_WORLD_IF, HelloWorldIfInterface))
typedef struct _HelloWorldIf HelloWorldIf; /* dummy object */
typedef struct _HelloWorldIfInterface HelloWorldIfInterface;
struct _HelloWorldIfInterface {
GTypeInterface parent;
gchar *(*get_hello)(HelloWorldIf *self);
};
GType hello_world_if_get_type(void);
gchar *hello_world_if_get_hello(HelloWorldIf *self);
G_END_DECLS
#endif /* __HELLO_WORLD_IF_H__ */
and in hello_world_if.c:
#include "hello_world_if.h"
G_DEFINE_INTERFACE(HelloWorldIf, hello_world_if, 0);
static void
hello_world_if_default_init(gpointer g_class) {
/* Add properties and signals to the interface here */
}
gchar *
hello_world_if_get_hello(HelloWorldIf *self) {
g_return_if_fail(IS_HELLO_WORLD_IF(self));
HELLO_WORLD_IF_GET_INTERFACE(self)->get_hello(self);
}
But this doesn't compile:
$ make
gcc -g -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -c -o hello_world_if.o hello_world_if.c
hello_world_if.c:3: error: expected declaration specifiers or ‘...’ before ‘hello_world_if’
hello_world_if.c:3: error: expected declaration specifiers or ‘...’ before numeric constant
hello_world_if.c:3: warning: data definition has no type or storage class
make: *** [hello_world_if.o] Error 1
From reading other answers here it seems this "expected declaration specifiers" message often means a necessary header file hasn't been included or has been included too late. But I'm not sure how that could be the case here. (Specifically, adding #include <glib.h> or #include <glib-object.h> to the C file doesn't change anything.)
I must be missing something simple but I just don't see it. Help?
Turns out there's a simple explanation: The G_DEFINE_INTERFACE macro was added in GLib 2.24.0, but I'm using version 2.22.5 (the standard on CentOS 6.3). I'll need to either build and install a newer version of GLib or dig up older reference documentation—the website doesn't go back further than 2.26.1.

Resources