【问题标题】:GCC with -std=c99 complains about not knowing struct timespec带有 -std=c99 的 GCC 抱怨不知道 struct timespec
【发布时间】:2011-04-21 23:18:33
【问题描述】:

当我尝试在 Linux 上使用 gcc -std=c99 编译它时,编译器抱怨不知道 struct timespec。但是,如果我在没有 -std=c99 的情况下编译它,一切正常。

#include <time.h>

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

为什么会这样?有没有办法让它与-std=c99一起工作?

【问题讨论】:

    标签: c posix c99 timespec


    【解决方案1】:

    显式启用 POSIX 功能

    timespec 来自 POSIX,因此您必须“启用”POSIX 定义:

    #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;
    }
    

    顶部的节是我目前使用的 - 它根据您使用的是 C99 还是 C89 编译器触发来自单一 UNIX 规范 (SUS) 的定义。

    • 如果您想要POSIX 2008 (SUS v4) 材料,请使用_XOPEN_SOURCE 700
    • 如果您想要POSIX 2004 (SUS v3) 材料,请使用_XOPEN_SOURCE 600
    • 如果您想要POSIX 1995 (SUS v2, 1997) 材料,请使用_XOPEN_SOURCE 500

    如 cmets 中所述,使用 _XOPEN_SOURCE 严格启用了严格 POSIX 之上的 XSI(X/开放系统接口)扩展,但您很少需要 POSIX 而不是 XSI。您通常应该指定_XOPEN_SOURCE,而不是使用_POSIX_C_SOURCE。有关功能宏的更多信息,请参阅 The Compilation Environment 上的 (POSIX 2018)。

    对于我在 2010 年的系统,POSIX 2008 不如 POSIX 2004 广泛可用,所以这就是我使用的 - 但 YMMV。请注意,SUS v3 和 v4 都需要 C99 编译。至少在 Solaris 上,使用 C89 失败了。

    GCC 提供-std=gnuXX 选项

    如果您将-std=c11 指定给 GCC(或 Clang 模拟 GCC),则仅启用标准 C 定义。如果您使用-std=gnu11,则 POSIX 和标准 C 的其他扩展默认是可见的。

    请注意,GCC 4.x 和更早版本默认使用-std=gnu90(对应于 C90 加扩展)。 GCC 5.x 及更高版本默认使用-std=gnu11。从来没有默认启用 -std=gnu99 的 GCC 版本。

    使用header控制POSIX版本信息

    我现在(2019 年)使用标头来封装此信息,以便将来的更改只需要更改单个标头,而不需要更改使用 POSIX 功能的每个源文件。随着时间的推移和 POSIX 2008 的流行,从多个源文件中编辑旧节变得很痛苦。

    /*
    @(#)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 */
    

    您可以使用此标头中的信息,而无需 Stack Overflow 使用的“CC by-sa 3.0”许可通常要求的归属和版权声明。此代码可在 GitHub 上我的 SOQ(堆栈溢出问题)存储库中以文件 posixver.h 的形式在 src/libsoq 子目录中找到。

    C11 定义struct timespec

    请注意,C11 定义了 struct timespec,并且这样做的方式与 POSIX(首先定义它)兼容。

    标题&lt;time.h&gt; 定义类型。其中三个使用它的函数在&lt;threads.h&gt; 中声明,另一个在&lt;time.h&gt; 中声明:

    当然,这些也是 C17 (C18) 的一部分。对于要定义的 struct timespec 类型,您必须使用 -std=c11 或类似名称进行编译(GCC 9.2.0 似乎同时识别 -std=c17-std=c18,以及 -std=c2x 用于标准的下一版本)自动。

    【讨论】:

    • 如果您只需要 POSIX,您应该将 _POSIX_C_SOURCE 定义为正确的值。 _XOPEN_SOURCE 用于 XSI 扩展。
    • @R..:是的,你说得对。但是,在实践中,您真的只需要 POSIX 而不需要 XSI 吗?如果是这样,您可以阅读并设置 POSIX。对于大多数人来说,大多数时候,给出的解决方案是明智的。
    • 在最新的 SUS 中,几乎所有有价值的功能都已移至基础,而 XSI 主要是遗留接口。当然,我说“大部分”是在掩饰我的背部。 ;-)
    • _XOPEN_SOURCE_POSIX_C_SOURCE 相比确实带来了一些有用的东西,例如 strdup()、strptime()、srandom()、realpath()、lockf() 和一些大文件支持东西。
    【解决方案2】:

    我建议使用-std=gnu99 进行编译。

    对此进行详细说明。默认情况下,gcc 使用 -std=gnu89 进行编译。以下是以下源代码的结果。

    #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
    

    【讨论】:

    • 不是这个问题的真正答案
    • 他在比较 -std=gnu89 和 -std=c99。更正确的比较是 -std=gnu89 到 -std=gnu99。虽然我同意乔纳森的回答更好地解释了这里发生的事情。
    • 对这个答案的反对意见是完全没有根据的。很明显,OP 将gnu89c99 进行比较,这就是出现错误的原因,并表明c89 也会出现同样的错误。这是有用的补充信息。
    【解决方案3】:

    将 -D_GNU_SOURCE 添加到您的 CFLAGS 也可以。

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

    查看 /usr/include/time.h。这是包装 timespec 定义的预处理器条件。 _GNU_SOURCE 启用 __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.  */
     }; 
    

    【讨论】:

      猜你喜欢
      • 2017-01-17
      • 2020-09-01
      • 2015-10-03
      • 2015-05-09
      • 1970-01-01
      • 1970-01-01
      • 2016-08-25
      • 2012-05-13
      相关资源
      最近更新 更多