`O_DIRECT' undeclared

· 408 words · 1 minute read

用 gcc 编译代码时报错:'O_DIRECT' undeclared. 看操作历史,之前一直用的 g++ 没报错。感觉有点奇怪。加上参数 -E 导出预处理过程对比了一下: 处理的文件都一样,但预处理的结果不一样。那就是 gcc 和 g++ 默认预定义的宏有区别了。

看了一下头文件:

/* file: /usr/include/bits/fcntl-linux.h */
#ifdef __USE_GNU
# define O_DIRECT   __O_DIRECT   /* Direct disk access.  */
# define O_NOATIME  __O_NOATIME  /* Do not set atime.  */
# define O_PATH     __O_PATH     /* Resolve pathname but do not open file.  */
# define O_TMPFILE  __O_TMPFILE  /* Atomically create nameless file.  */
#endif

原来 O_DIRECT 这些宏不是标准宏。看看 gcc 和 g++ 各自的预定义宏:

$ gcc -E -xc -dM /dev/null | grep GNU
#define __GNUC_PATCHLEVEL__ 0
#define __GNUC__ 8
#define __GNUC_RH_RELEASE__ 21
#define __GNUC_STDC_INLINE__ 1
#define __GNUC_MINOR__ 5

$ g++ -E -xc++ -dM /dev/null | grep GNU
#define __GNUC_PATCHLEVEL__ 0
#define __GNUC__ 8
#define __GNUG__ 8
#define __GNUC_RH_RELEASE__ 21
#define __GNUC_STDC_INLINE__ 1
#define __GNUC_MINOR__ 5
#define _GNU_SOURCE 1

虽然没有 __USE_GNU 但是明显 g++ 预定义了 _GNU_SOURCE 而 gcc 没有。在 man (2) open 中反查 _GNU_SOURCE,看到 STANDARDS 一节写到:

STANDARDS
  open(), creat() SVr4, 4.3BSD, POSIX.1-2001, POSIX.1-2008.
  
  openat(): POSIX.1-2008.
  
  The O_DIRECT, O_NOATIME, O_PATH, and O_TMPFILE flags are Linux-specific.  One must define
  _GNU_SOURCE to obtain their definitions.

也就是说,O_DIRECT, O_NOATIME, O_PATH 以及 O_TMPFILE 是特定于 Linux 的宏定义。要想使用这些宏,需要先定义 _GNU_SOURCE.

grep -r '#if.*_GNU_SOURCE' /usr/include/ 可以看到一个头文件/usr/include/features.h. 查看其内容,果然有:

#ifdef  _GNU_SOURCE
# define __USE_GNU    1
#endif
c++
comments powered by Disqus