为什么 strerror_r 在使用 gnu90 和 c90 标准编译时表现不同?

Why does strerror_r behave differently when compiled with gnu90 and c90 standards?

这是我的程序。

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

int main()
{
        char errbuf[256];

        errno = 0;
        strtoul("99999999999999999999999999999999999999999999", NULL, 0);
        strerror_r(errno, errbuf, sizeof errbuf);
        printf("strerror_r: %s\n", errbuf);

    return 0;
}

当我用 -std=gnu90-std=gnu99 编译它时,我得到了预期的输出。

susam@nifty:~/lab/linux$ rm -f a.out && gcc -std=gnu90 -Wall -Wextra -pedantic foo.c && ./a.out 
strerror_r: Numerical result out of range
susam@nifty:~/lab/linux$ rm -f a.out && gcc -std=gnu99 -Wall -Wextra -pedantic foo.c && ./a.out 
strerror_r: Numerical result out of range

但是当我用 -std=c90-std=c99 编译它时,我收到警告并且我没有看到 strerror_r 将字符串放入 errbuf.

lone@debian:~/lab/linux$ rm -f a.out && gcc -std=c90 -Wall -Wextra -pedantic foo.c && ./a.out
foo.c: In function ‘main’:
foo.c:12:2: warning: implicit declaration of function ‘strerror_r’ [-Wimplicit-function-declaration]
  strerror_r(errno, errbuf, sizeof errbuf);
  ^
strerror_r:
lone@debian:~/lab/linux$ rm -f a.out && gcc -std=c99 -Wall -Wextra -pedantic foo.c && ./a.out
foo.c: In function ‘main’:
foo.c:12:2: warning: implicit declaration of function ‘strerror_r’ [-Wimplicit-function-declaration]
  strerror_r(errno, errbuf, sizeof errbuf);
  ^
strerror_r:

我使用 -std=c90-std=c99 时出了什么问题?

对于 -std=c89,您要求实现专门提供 ISO 9899:1989 标识符部分的声明。标识符 strerror_r 不是 C89(或 C99)的一部分,因此没有原型。因此,您会收到有关隐式声明的警告。

如果您查看相关的 header,您可能会发现 strerror_r 原型被掩埋在 #ifdef 的迷宫中。 -std 选项更改影响原型可见性的 pre-defined 宏集。

strerror_r(3) 说:

The XSI-compliant strerror_r() is preferred for portable applications. It returns the error string in the user-supplied buffer buf of length buflen.

The GNU-specific strerror_r() returns a pointer to a string containing the error message. This may be either a pointer to a string that the function stores in buf, or a pointer to some (immutable) static string (in which case buf is unused). If the function stores a string in buf, then at most buflen bytes are stored (the string may be truncated if buflen is too small and errnum is unknown). The string always includes a terminating null byte.

所以这不仅仅是声明是否可见的问题(这本身就是一个相当大的问题 - 当您收到“隐式声明”警告时,您根本不应该期望该程序能够运行.) 这也是您调用的函数版本的问题。 GNU 版本有时 returns 指向库中常量字符串的指针,而不是将字符串复制到调用者提供的缓冲区。

strerror_r 的基本目的不是“我想要这个缓冲区中的字符串”;它是“我想要一个以后不会被库覆盖的字符串。”