GCC with -std=c99 complains about not knowing struct timespec

19,345

Solution 1

Explicitly enabling POSIX features

The timespec comes from POSIX, so you have to 'enable' POSIX definitions:

#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif /* __STDC_VERSION__ */

#include <time.h>

void blah(struct timespec asdf)
{
}

int main()
{
    struct timespec asdf;
    return 0;
}

The stanza at the top is what I currently use - it triggers the definitions from Single UNIX Specification (SUS) based on whether you're using a C99 or C89 compiler.

  • If you want the POSIX 2008 (SUS v4) material, use _XOPEN_SOURCE 700
  • If you want the POSIX 2004 (SUS v3) material, use _XOPEN_SOURCE 600
  • If you want the POSIX 1995 (SUS v2, 1997) material, use _XOPEN_SOURCE 500

As noted in the comments, using _XOPEN_SOURCE strictly enables the XSI (X/Open System Interface) extensions over strict POSIX, but it is very rare for you to want POSIX and not XSI. You should normally specify _XOPEN_SOURCE and not futz with _POSIX_C_SOURCE. See (POSIX 2018) on The Compilation Environment for more information about feature macros.

For my systems in 2010, POSIX 2008 was not as widely available as POSIX 2004, so that's what I used - but YMMV. Note that SUS v3 and v4 both require C99 compilation. On Solaris, at least, using C89 failed.

GCC provides -std=gnuXX options

If you specify -std=c11 to GCC (or Clang emulating GCC), then only the standard C definitions are enabled. If you use -std=gnu11, then POSIX and other extensions to standard C are visible by default.

Note that GCC 4.x and earlier used -std=gnu90 (corresponding to C90 plus extensions) by default. GCC 5.x and later use -std=gnu11 by default. There was never a version of GCC that enabled -std=gnu99 by default.

Use a header to control the POSIX version information

I now (2019) use a header to encapsulate this information so that future changes only require the change to a single header, not to every source file that uses POSIX features. It was painful editing the old stanza out of multiple source files as time passed and POSIX 2008 became prevalent.

/*
@(#)File:           $RCSfile: posixver.h,v $
@(#)Version:        $Revision: 1.4 $
@(#)Last changed:   $Date: 2017/06/18 00:15:42 $
@(#)Purpose:        Request appropriate POSIX and X/Open Support
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 2010-2017
*/

/*TABSTOP=4*/

#ifndef JLSS_ID_POSIXVER_H
#define JLSS_ID_POSIXVER_H

/*
** Include this file before including system headers.  By default, with
** C99 support from the compiler, it requests POSIX 2008 support.  With
** C89 support only, it requests POSIX 1997 support.  Override the
** default behaviour by setting either _XOPEN_SOURCE or _POSIX_C_SOURCE.
*/

/* _XOPEN_SOURCE 700 is loosely equivalent to _POSIX_C_SOURCE 200809L */
/* _XOPEN_SOURCE 600 is loosely equivalent to _POSIX_C_SOURCE 200112L */
/* _XOPEN_SOURCE 500 is loosely equivalent to _POSIX_C_SOURCE 199506L */

#if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE)
#if defined(__cplusplus)
#define _XOPEN_SOURCE 700   /* SUS v4, POSIX 1003.1 2008/13 (POSIX 2008/13) */
#elif __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 700   /* SUS v4, POSIX 1003.1 2008/13 (POSIX 2008/13) */
#else
#define _XOPEN_SOURCE 500   /* SUS v2, POSIX 1003.1 1997 */
#endif /* __STDC_VERSION__ */
#endif /* !_XOPEN_SOURCE && !_POSIX_C_SOURCE */

#endif /* JLSS_ID_POSIXVER_H */

You may use the information from this header without the attribution and copyright notice normally required by the "CC by-sa 3.0" licence used by Stack Overflow. This code is available in my SOQ (Stack Overflow Questions) repository on GitHub as file posixver.h in the src/libsoq sub-directory.

C11 defines struct timespec

Note that C11 defines struct timespec, and does so in a way that is compatible with POSIX (which defined it first).

The header <time.h> defines the type. Three of the functions that use it are declared in <threads.h> and the other is in <time.h>:

These are also part of C17 (C18) of course. You would have to be compiling with -std=c11 or similar (GCC 9.2.0 seems to recognize both -std=c17 and -std=c18, and -std=c2x for the next version of the standard) for the type struct timespec to be defined automatically.

Solution 2

I would recommend compiling with -std=gnu99.

To elaborate on this. By default, gcc compiles with -std=gnu89. Here are the results for the following source code.

#include <time.h>

int main() {
    struct timespec asdf;
    return 0;
}

[1:25pm][wlynch@cardiff /tmp] gcc -std=gnu89 foo.c
[1:26pm][wlynch@cardiff /tmp] gcc -std=gnu99 foo.c

[1:25pm][wlynch@cardiff /tmp] gcc -std=c89 foo.c
foo.c: In function ‘main’:
foo.c:4: error: storage size of ‘asdf’ isn’t known

[1:26pm][wlynch@cardiff /tmp] gcc -std=c99 foo.c
foo.c: In function ‘main’:
foo.c:4: error: storage size of ‘asdf’ isn’t known

Solution 3

Adding -D_GNU_SOURCE to your CFLAGS will also work.

gcc test.c -o test -std=c99 -D_GNU_SOURCE

Have a look at /usr/include/time.h. This is the preprocessor conditional that wraps the timespec definition. _GNU_SOURCE enables __USE_POSIX199309.

#if (!defined __timespec_defined                    \
 && ((defined _TIME_H                       \
  && (defined __USE_POSIX199309                 \
      || defined __USE_ISOC11))                 \
 || defined __need_timespec))
 # define __timespec_defined 1                                                                                                                                                                                                                 
 struct timespec
 {
    __time_t tv_sec;        /* Seconds.  */
    __syscall_slong_t tv_nsec;  /* Nanoseconds.  */
 }; 
Share:
19,345

Related videos on Youtube

Nils
Author by

Nils

Twitter: http://twitter.com/#!/NightLifeLover

Updated on January 29, 2020

Comments

  • Nils
    Nils over 4 years

    When I try to compile this on Linux with gcc -std=c99, the compiler complains about not knowing struct timespec. However if I compile this without -std=c99 everything works fine.

    #include <time.h>
    
    int main(void)
    {
      struct timespec asdf;
      return 0;
    }
    

    Why is this and is there a way to still get it to work with -std=c99?

  • Karel Petranek
    Karel Petranek over 13 years
    Not really an answer to the question
  • Bill Lynch
    Bill Lynch over 13 years
    He's comparing -std=gnu89 to -std=c99. The more correct comparison would be -std=gnu89 to -std=gnu99. Although I do agree that Jonathan's answer explains what is going on here much better.
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE over 13 years
    You should define _POSIX_C_SOURCE to the proper values if you just want POSIX. _XOPEN_SOURCE is for XSI extensions.
  • Jonathan Leffler
    Jonathan Leffler over 13 years
    @R..: Yes, you are pedantically correct. However, in practice, do you really want only POSIX and not XSI? If so, you can read up and set just POSIX. For most people, most of the time, the solution given is sensible.
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE over 13 years
    In the latest SUS, pretty much all worthwhile functionality has been moved to base, and XSI is mostly legacy interface cruft. Of course I'm covering my back by saying "mostly". ;-)
  • caf
    caf over 13 years
    The downvotes on this answer are completely unwarranted. It makes it clear that the OP is comparing gnu89 with c99, which is why the error arises, and shows that the same error arises with c89. It is useful supplemental information.
  • winbina
    winbina about 13 years
    _XOPEN_SOURCE does bring in some useful stuff compared to _POSIX_C_SOURCE, for example strdup(), strptime(), srandom(), realpath(), lockf(), and some large file support stuff.