为什么我可以在gcc -std=c11中使用gets()函数?

13

gets()函数已从C语言中移除。标准库中不再存在此函数。

但我编译以下代码:

#include <stdio.h>

int main (void)
{
  (void) gets (NULL);
}

使用

gcc -std=c11 -pedantic-errors -Wall -Wextra

它可以编译而没有给出任何错误或警告。同样地,

#include <stdio.h>

int gets;

int main (void)
{}

编译会出错(错误:'gets' 作为不同类型的符号重新声明)。

在标准的第4节一致性§6中,我们可以读到:

  

一个一致的实现可能有扩展(包括额外的库函数),前提是它们不会改变任何严格一致程序的行为。

鉴于上述内容,我认为gcc即使在pedantic模式下也不符合标准。这是有原因的吗? 这是故意的还是一个错误?

GCC版本4.9.1。

编辑:

gcc --version
gcc (x86_64-win32-seh-rev1, Built by MinGW-W64 project) 4.9.1

1
这里是GCC 4.8.2。在严格模式下,第一个片段将无法编译,因为gets从未定义。在非严格模式下,我会收到“警告:'gets'函数是危险的,不应使用。”的提示。第二个片段没有问题,因为没有任何东西阻止您声明一个名为gets的符号。例如,int printf;是完全合法的。我是否错过了问题的要点? - Stefano Sanfilippo
2
我正在寻找一个特定于gcc 4.9.1的错误,因为版本4.8.2和> 4.9.2会失败。 - edmz
11
MinGW使用微软的标准库,但它甚至不完全支持C99。 - interjay
2
@haccks:不,gcc从来没有支持过gets -- 或者说fgets。如果某个实现支持gets,那么它是由库而不是编译器实现的。 - Keith Thompson
2
@haccks:是和不是。在GNU C库提供的<stdio.h>头文件中,gets仍然被声明,但该声明被#if !defined __USE_ISOC1 ... #endif所包围。实现仍然存在,但以一种允许用户代码定义具有相同名称的函数的方式存在。 - Keith Thompson
显示剩余9条评论
3个回答

12

gcc只是编译器,而非整个实现。

在我的系统上(Linux Mint 17.3,gcc 4.8.4,GNU libc 2.19),我得到:

$ gcc -std=c11 -pedantic-errors -Wall -Wextra -c c.c
c.c: In functionmain’:
c.c:5:3: error: implicit declaration of functiongets[-Wimplicit-function-declaration]
   (void) gets (NULL);
   ^

为了正确诊断错误,实现必须符合规范。这意味着编译器(一开始就从未提供gets函数)和库都必须符合规范。

您正在使用仍然提供gets函数的库。因此,整个实现(由gcc编译器、库和其他几个组件组成)不符合C11标准。

底线:这不是一个gcc问题,gcc对此无能为力。(嗯,它可以针对gets发出特定的诊断,但然后它就必须确定它不是对同名用户定义函数的有效调用。)


虽然C标准库已经放弃了gets函数,但GNU C库仍然包含此函数。 - haccks
2
将我的回复复制到您的另一个评论中:@haccks:是和不是。在GNU C库提供的<stdio.h>头文件中,gets仍然被声明,但该声明被#if !defined __USE_ISOC1 ... #endif所包围。实现仍然存在,但以一种允许用户代码定义具有相同名称的函数的方式存在。 - Keith Thompson
你认为这是一个错误吗? - haccks
3
这是特定实现(MinGW)未符合C11标准的失败。 (另请参阅MinGW对“long double”的问题,这适用于C90、C99和C11。)当然,我会说这是一个错误。(但这是一个很容易避免的错误--即使您的编译器没有警告,请不要使用“gets”函数。) - Keith Thompson
感谢你纠正我。我很高兴你在将近一年后来到这篇文章中分享这些信息(有点惊讶!!)。 - haccks
显示剩余2条评论

1

你代码的关键行是:

#include <stdio.h>

你是否更新了系统的C库和头文件?它们也是C实现的一部分,与编译器一起使用。


我运行了 mingw-get updatemingw-get upgrade,但之后仍然出现相同的错误。 - Lundin
正如安德鲁所提到的,关键行是 #include <stdio.h>。你应该找到并分析 gcc 用于执行编译的 stdio.h 文件。那个文件可能仍然定义了 gets 函数。 - Valy

1

更新:这可能不是问题的答案,我尝试使其信息化。

我发现gcc提到gets不遵循C11标准,原因是某些库的问题glibc 2.16

查看gcc对C11的支持状态:https://gcc.gnu.org/wiki/C11Status 从上面的链接裁剪而来

但我找不到“库问题”的定义以及其他版本glibc的当前状态。

所以我在我的机器上尝试了ubuntu16.04,gcc版本为5.3.1 20160413,glibc版本为Ubuntu GLIBC 2.23。 我们可以在编译时得到足够的警告,但仍然可以执行输出的目标文件以实现“向后兼容性”。

warning: implicit declaration of function ‘gets’ [-Wimplicit-function-declaration]
warning: the `gets' function is dangerous and should not be used.

4
这是误导性的。gcc从未提供过gets函数,因此它也没有将其删除。这个函数是由库提供的,而不是由编译器提供的(这就是为什么状态页面称其为“库问题”)。 - Keith Thompson
@Keith Thompson。感谢您的回答!非常清晰和有帮助 :)。 - owlfox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接