【问题标题】:How to force g++ to respect #define _POSIX_C_SOURCE 200809L如何强制 g++ 尊重#define _POSIX_C_SOURCE 200809L
【发布时间】:2021-02-14 17:55:30
【问题描述】:

我需要在 Linux Debian Bullseye 上使用 strerror_r 将错误编号转换为使用 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.

我们有两种不同类型的返回值: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的默认线程保存版本?我需要那个版本。我该如何解决?


参考

【问题讨论】:

    标签: linux compiler-errors g++


    【解决方案1】:

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

    #define _POSIX_C_SOURCE 200112L
    #undef _GNU_SOURCE
    
    #include <string.h>
    #include <stdio.h>
    

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

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

    【讨论】:

    • 我知道这些指令必须在Feature Test Macros 中提到的最前面的位置。我在#include 指令后面的示例中设置它,以通过错误消息显示它已经预定义。但是通过所有尝试和错误,我监督将#undef _GNU_SOURCE 设置在第一个位置:-{感谢您的快速回答。
    • 刚刚查看了更多详细信息。因为 POSIX_C_SOURCE 200809L 已如错误消息所示定义,所以仅在第一个位置设置 #undef _GNU_SOURCE 或使用 -U_GNU_SOURCE 编译器选项就足够了。
    猜你喜欢
    • 2015-06-30
    • 2020-02-02
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    • 2020-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多