simplicio
simplicio

Reputation: 200

Trouble including function declaration for strptime()

Have a time date string I'd like to convert to a tm object. Google tells me the POSIX (but not the C) standard includes a function called strptime() that will do the job.

The man page says it's in <time.h> and that I need to include #define _XOPEN_SOURCE before I include the <time.h> file. Easy enough.

But I still get an implicit declaration warning from the compiler. I opened /usr/include/time.h and found the function declaration:

 # ifdef __USE_XOPEN
/* Parse S according to FORMAT and store binary time information in TP.
   The return value is a pointer to the first unparsed character in S.  */
extern char *strptime (const char *__restrict __s,
               const char *__restrict __fmt, struct tm *__tp)
     __THROW;
#endif

So it looks like I need #define _USE_XOPEN instead.

Except that doesn't work either. The compiler still isn't seeing the declaration.

Any ideas. I'm using a relatively recent version of Linux (Mint) with gcc 5.4.0.

Upvotes: 3

Views: 6505

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 754540

Converting comments into an answer.

To fix this, your options include using -std=gnu11 instead of -std=c11 on the GCC command line, or using #define _XOPEN_SOURCE 700 or equivalent (e.g. -D_XOPEN_SOURCE=700 on the command line). The 700 identifies POSIX 2008; 600 or 500 identify earlier versions of POSIX or X/Open.

In theory, you could also use _POSIX_C_SOURCE 200809L (see POSIX Compilation environment), but that doesn't expose everything that _XOPEN_SOURCE 700 exposes so it is usually better to use the latter.

Note that the POSIX specification of strptime() is annotated as an XSI extension, which means you must set _XOPEN_SOURCE; setting _POSIX_C_SOURCE alone is not sufficient.

Test code

This test code prints the address of the strptime function; it won't compile if strptime() is not declared.

#define _XOPEN_SOURCE 700
#include <time.h>
#include <stdio.h>

int main(void)
{
    printf("%p\n", (void *)strptime);
    return 0;
}

That should compile for you with gcc -std=c11 -Wall -c test-strptime.c. If you add -ansi to the options, you reset the standard back to C90. GCC 5.4.0 should default to C11 (effectively -std=gnu11) unless someone did something horrible in the build of GCC that you're using (which is unlikely).

Note that the compiler unsets and then sets __USE_XOPEN based on settings like _XOPEN_SOURCE and trying to set it manually doesn't work reliably.

Position matters

You must specify the #define _XOPEN_SOURCE 700 before the first system header is included (whether included directly or indirectly). If you include a system header before trying to set _XOPEN_SOURCE, the settings have been determined and your subsequent operations are effectively ignored. POSIX says (at the 'compilation environment' link already given):

In the compilation of an application that #defines a feature test macro specified by POSIX.1-2008, no header defined by POSIX.1-2008 shall be included prior to the definition of the feature test macro. This restriction also applies to any implementation-provided header in which these feature test macros are used. If the definition of the macro does not precede the #include, the result is undefined.

One common undefined result is that your attempt to set/change the POSIX version is completely ignored.

Upvotes: 9

Related Questions