如何强制 g++ 遵守#define _POSIX_C_SOURCE 200809L

How to force g++ to respect #define _POSIX_C_SOURCE 200809L

我需要使用 strerror_r 将错误编号转换为在 Linux Debian Bullseye 上使用 g++ 编译的人类可读消息。手册页注释:

int strerror_r(int errnum, char *buf, size_t buflen);
           /* XSI-compliant */

char *strerror_r(int errnum, char *buf, size_t buflen);
           /* GNU-specific */

strerror_r():
   The XSI-compliant version is provided if:
   (_POSIX_C_SOURCE >= 200112L) && !  _GNU_SOURCE
   Otherwise, the GNU-specific version is provided.

我们有两种不同类型的 return 值:intchar*,具体取决于 _POSIX_C_SOURCE 定义的版本。我有这个小测试程序:

~$ cat strerror_r.c
#include <string.h>
#include <stdio.h>

// #define _POSIX_C_SOURCE 200112L
// #undef _GNU_SOURCE

#define ERROR_BUFFER_LEN (size_t)256

int main(int argc, char **argv)
{
#if _POSIX_C_SOURCE < 200112L
    char* ret;
#else
    int ret;
#endif
    char errorBuffer[ERROR_BUFFER_LEN];
    int errno;

    errno = 0;
    ret = strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
    fprintf(stderr, "Error message by pointer = '%s'\n", ret);
    fprintf(stderr, "Content of errorBuffer =  '%s'\n", errorBuffer);

    return 0;
}

如果我用 gcc 编译它,一切都符合预期:

$ gcc strerror_r.c && ./a.out; rm a.out
Error message by pointer = '(null)'
Content of errorBuffer =  'Success'

如果我用 g++ 编译它,我得到这个:

$ g++ strerror_r.c && ./a.out; rm a.out
strerror_r.c: In function ‘int main(int, char**)’:
strerror_r.c:24:21: error: invalid conversion from ‘char*’ to ‘int’ [-fpermissive]
   24 |     ret = strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
      |           ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                     |
      |                     char*
rm: cannot remove 'a.out': No such file or directory

如果我试图通过取消注释强制使用所需的版本

#define _POSIX_C_SOURCE 200112L
#undef _GNU_SOURCE

我得到:

$ g++ strerror_r.c && ./a.out; rm a.out
strerror_r.c:7: warning: "_POSIX_C_SOURCE" redefined
    7 | #define _POSIX_C_SOURCE 200112L
      |
In file included from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,
                 from /usr/include/string.h:26,
                 from strerror_r.c:3:
/usr/include/features.h:281: note: this is the location of the previous definition
  281 | # define _POSIX_C_SOURCE 200809L
      |
strerror_r.c: In function ‘int main(int, char**)’:
strerror_r.c:24:21: error: invalid conversion from ‘char*’ to ‘int’ [-fpermissive]
   24 |     ret = strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
      |           ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                     |
      |                     char*
rm: cannot remove 'a.out': No such file or directory

我在这里缺少什么?为什么g++不编译strerror_r的默认线程保存版本?我需要那个版本。我该如何解决?


参考

您需要在包含任何 header 文件之前指定 #define#undef 指令,因此前几行应如下所示:

#define _POSIX_C_SOURCE 200112L
#undef _GNU_SOURCE

#include <string.h>
#include <stdio.h>

那是因为它们包含的 header 文件或内部 header 文件需要定义这些值才能选择正确的变体。如果您在包含 header 之后定义它们,则 header 看不到正确的值并且它们不包含您想要的版本。

人们通常在命令中指定这些值,例如使用 -D-U 参数,因此它们总是在包含 header 个文件之前指定。