关于C#:为什么sys / stat.h不能用-std = c1x定义ino_t?

Why won't sys/stat.h define ino_t with -std=c1x?

我正在编写一些C代码的奇怪问题。 请考虑以下代码:

1
2
#include <sys/stat.h>
ino_t inode;

根据POSIX.1-2008,头文件定义ino_t 1:

The header shall define the blkcnt_t, blksize_t, dev_t, ino_t, mode_t, nlink_t, uid_t, gid_t, off_t, and time_t types as described in .

当我尝试在Linux系统上的文件test.c中的位置上编译源代码时会发生这种情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat test.c
#include <sys/stat.h>
ino_t inode;
$ uname -srm
Linux 3.8.0-26-generic x86_64
$ lsb_release -d
Description:    Ubuntu 13.04
$ gcc -c test.c
$ gcc -std=c90 test.c
test.c:2:1: error: unknown type name 'ino_t'
$ gcc -std=c99 test.c    
test.c:2:1: error: unknown type name 'ino_t'
$ gcc -std=c1x test.c
test.c:2:1: error: unknown type name 'ino_t'

当我指定任何-std选项时,为什么ino_t的定义不会显示?


我的fstat手册页也说包含sys/types.h,这解决了我的问题。 sys/stat.hino_t的定义受特征宏__USE_XOPEN__USE_XOPEN2K的保护。 sys/types.h中的定义不受这种保护。

手册页也说包含unistd.h,但这不是解决问题所必需的。

根据feature_test_macros的手册页:

__STRICT_ANSI__
ISO Standard C. This macro is implicitly defined by gcc(1) when
invoked with, for example, the -std=c99 or -ansi flag.

我想这意味着任何XOPEN功能也都会被关闭。然而,我无法找到任何描述。

附:似乎R ..(见下文)认为这也在feature_test_macros的手册页中有所描述,但是我的有限大脑无法找到确切的措辞,所以我想将其作为练习留给读者。如果它在任何地方被描述,那么我希望它确实在那个手册页中。

请注意这个答案的要点如下:

Thou shall include all include files mentioned in a manual page and not try to reverse engineer which ones may not be needed.


如果您使用-std=gnuXX而不是-std=cXX,您的程序将编译无怨言。

1
2
3
$ cc -std=c11 -fsyntax-only test.c ; echo $?
test.c:2:1: error: unknown type name ‘ino_t’; did you mean ‘__ino_t’?
1

1
2
$ cc -std=gnu11 -fsyntax-only test.c ; echo $?
0

许多人不能正确理解-std=cXX选项的效果。它们本身并不告诉GCC严格遵守(例如诊断所有GNU扩展的使用)。如果您想要严格一致,您还必须提供选项-Wall -Wpedantic

-std=cXX模式和相应的-std=gnuXX模式之间只有三个区别,其中两个通常不是您想要的:

  • -std=cXX模式下禁用应用程序命名空间中特定于系统的预定义宏。这是一件好事;应用程序命名空间预定义的宏充其量是混乱,最坏的情况是破坏合法代码。但是,众所周知,要破坏仍在寻找这些宏的系统头文件。

  • Trigraph在-std=cXX模式下启用,在-std=gnuXX模式下禁用。你不想要三角形;它们在发明时已经过时了,而且很久以前它们应该已经从C标准中删除了。

  • -std=cXX模式下,GNU libc将尝试最小化在其标头中可见的指定C标准之上和之外的扩展数。 (注意:GCC可以使用的许多其他C库都不会这样做。)对于像sys/stat.h这样的标题不属于C标准的情况,这意味着"仅公开那些特征我们支持这个标题的最旧版本,"这通常是非常古老和有限的,如POSIX.1-1993。这就是绊倒你的原因。您可以通过定义功能测试宏来解决它,以指导GNU libc公开更新的POSIX等功能。

  • 如果你是从头开始编写一个新的C程序,我建议你使用-Wall-Wpedantic(可能还有一堆其他-W开关),但我不建议使用-std=cXX,因为唯一的正面效果是关闭系统特定的预定义,这可能会破坏系统头。通过尝试找到一个_POSIX_C_SOURCE_XOPEN_SOURCE设置可以为您提供所需的一切(特别是如果您或第三方代码),直接使用_GNU_SOURCE或等同于未来也几乎总是不那么麻烦bundle,可能会使用弃用但仍然常见的函数,如gettimeofday