GCC с -std = c99 жалуется, что не знает struct timespec

Когда я пытаюсь скомпилировать это в Linux с помощью gcc -std=c99, компилятор жалуется на незнание struct timespec. Однако, если я скомпилирую это без -std=c99, все будет хорошо.

#include <time.h>

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

Почему это и есть способ все еще заставить его работать с -std=c99?

Ответ 1

Явное включение функций POSIX

Временная спецификация происходит из 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;
}

Раздел в верхней части - это то, чем я сейчас пользуюсь - он вызывает определения из Single UNIX Specification (SUS), основанные на том, используете ли вы компилятор C99 или C89.

  • Если вы хотите материал POSIX 2008 (SUS v4), используйте _XOPEN_SOURCE 700
  • Если вы хотите материал POSIX 2004 (SUS v3), используйте _XOPEN_SOURCE 600
  • Если вы хотите материал POSIX 1995 (SUS v2, 1997), используйте _XOPEN_SOURCE 500

Обратите внимание, что использование _XOPEN_SOURCE строго разрешает расширения XSI по сравнению со строгим POSIX, но очень редко вы _XOPEN_SOURCE POSIX, а не XSI. Обычно вы должны указать _XOPEN_SOURCE а не futz с _POSIX_C_SOURCE. См. (POSIX 2018) в среде компиляции для получения дополнительной информации о функциональных макросах.

Для моих систем в 2010 году POSIX 2008 был не так широко доступен, как POSIX 2004, так что то, что я использовал - но YMMV. Обратите внимание, что для SUS v3 и v4 требуется компиляция C99. На Солярисе, по крайней мере, использование 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=gnu11. Никогда не было версии GCC, которая бы -std=gnu99 по умолчанию.

Используйте заголовок для управления информацией о версии 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 */

Вы можете использовать информацию из этого заголовка без указания авторства и авторских прав, обычно требуемых лицензией "CC by-sa 3.0", используемой Stack Overflow. Этот код доступен в моем репозитории SOQ (вопросы о переполнении стека) на GitHub в виде файла posixver.h в posixver.h src/libsoq.

Ответ 2

Я бы порекомендовал компиляцию с -std=gnu99.

Продумать это. По умолчанию gcc компилируется с -std = gnu89. Ниже приведены результаты для следующего исходного кода.

#include <time.h>

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

[1:25pm][[email protected] /tmp] gcc -std=gnu89 foo.c
[1:26pm][[email protected] /tmp] gcc -std=gnu99 foo.c

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

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