为什么C99不允许隐式声明gets()函数?

4

我开始学习C语言编程,参考的教材中有一些源代码使用了gets()函数,我的IDLE也能够识别它。但是,在编译时,我的编译器不同意此操作。

有谁能帮我解决这个问题吗?我在主函数中使用了gets()函数,并使用clang作为编译器。


8
可能是因为 gets 函数已经完全移除了。你收到的错误消息是什么?我很确定这是一个链接器错误。而且 永远不要 使用隐式声明,它们是上个世纪遗留下来的东西。 - Jabberwocky
2
@Mr. Anderson,函数gets不安全,不再受C标准支持。请改用函数fgets。您可以在互联网上找到它的描述。 - Vlad from Moscow
4
@Mr.Anderson 好的,实际上这是一个编译器错误。显然你使用的C编译器根本不允许隐式声明,这是非常好的事情。gets函数已经被废弃了大约20年。不要使用它。请阅读this - Jabberwocky
@VladfromMoscow,它确实起作用了。非常感谢您。 :-) - Mr. Anderson
2
三件事情。1:隐式声明只对返回“int”的函数有效;gets()返回char *,因此隐式声明gets()是错误的。2:自C99起,不再允许隐式声明。3:自C2011起,标准库中已删除了gets(),因为它是危险的,并且在您的代码中引入故障点。永远不要使用它,即使是在玩具代码中也不行。 - John Bode
显示剩余5条评论
3个回答

7

继续阐述我的评论:

首先,永远不要使用gets(),即使在玩具代码中也是如此。如果在示例程序中看到它,请忽略该示例并继续执行。它已经在C99中被弃用,并在C2011中从标准库中完全删除,因为它是一个主要的安全漏洞。由于这个函数引起的麻烦值得打破30多年的遗留代码。

其次,在C89及更早版本中,如果编译器在看到声明或定义之前看到函数调用,则会假定函数返回int - 也就是说,函数具有隐式int声明。如果您在同一翻译单元中稍后有一个返回int的函数定义,那么就没问题了:

int foo( void )
{
  int x = bar(); // bar *implicitly* declared to return int
}

int bar( void ) // implicit declaration matches definition, we're good
{
  return some_integer_value;
}

然而,如果bar没有返回一个int,你会得到一个错误,因为隐式的int声明与非int定义不匹配。 gets()返回char *,而不是int,所以无论如何隐式声明gets都是不正确的。
C99完全删除了隐式的int声明 - 自此之后,所有函数在调用之前必须被声明或定义。 编辑 你收到隐式声明错误的最可能原因是你的编译器足够新,已经没有stdio.h中的gets声明。

1
你收到"gets的隐式声明不被允许"这样的信息,原因与你尝试调用my_undeclared_function会得到"my_undeclared_function的隐式声明不被允许"信息相同。现在,gets不再是标准C库函数。
更详细地解释一下:在现代C中,如果你编写以下代码:
int main()
{
    f();
}

int f()
{
    return 0;
}

通常你会收到像“在C99中无效的函数‘f’的隐式声明”这样的消息。曾经,如果你调用了编译器还未知晓的函数,它会默认该函数返回一个int类型的值,但是这个假设在C99中已经被移除了。
另一方面,如果你写成:
#include <stdio.h>

int main()
{
    char line[100];
    printf("type something:\n");
    fgets(line, sizeof(line), stdin);
    printf("you typed: %s", line);
    return 0;
}

你将不会收到有关函数printffgets的消息。这些编译器知道的函数:它们的声明在<stdio.h>中。

但如果您编写:

#include <stdio.h>

int main()
{
    char line[100];
    printf("type something:\n");
    gets(line);
    printf("you typed: %s", line);
    return 0;
}

你将再次收到有关函数gets()的消息,因为编译器不知道gets是什么函数。它不是标准函数,也没有在<stdio.h>中声明。
曾经,gets是一个标准函数,并且在<stdio.h>中声明过,但它是一个极其不合理和危险的函数,因此已从标准中删除。你所阅读的书推荐使用它已经过时了。

这不正确。在C99中,gets被标记为过时的,但它并没有从语言中删除。 - Lundin
@Lundin,我并没有说gets在C99中被移除了。我不确定它是在什么时候被移除的,但如果你说是在C11中,我相信你。 - Steve Summit

0

你没有包含 #include <stdio.h>,就是这么简单。

在 C99 中,如果你使用这个确切的代码,你会得到一个错误:

int main (void)
{
  char buf[10];
  gets(buf);
  return 0;
}

包括 stdio.h 可以解决这个问题。不过值得注意的是,在 C99 中,gets 被标记为过时函数,并在 C11 中完全从语言中删除。因此,以下代码将无法在标准 C(C11)中编译:
#include <stdio.h>

int main (void)
{
  char buf[10];
  gets(buf);
  return 0;
}

你可能会因为编译成标准 C 而不是 C99 而出错。

(注意,Windows Mingw 编译器特别可能使用 C11 编译器但是使用 C99 标准库,因此你可能会在使用它时得到一些奇怪的结果。)

请参见“gets” 函数为什么如此危险? 了解详情。


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