禁用警告:通过头文件在GCC中使用`gets'函数是危险的?

8

我在我的C代码中使用了gets()函数。虽然代码可以正常运行,但是我收到了一个警告信息。

(.text+0xe6): warning: the `gets' function is dangerous and should not be used.

我希望这个警告信息不要弹出。有没有什么方法?
我在想,通过创建一个头文件来禁用某些警告可能存在这样的可能性。或者在编译期间是否有任何选项可以达到我的目的?或者也许有一种特殊的使用gets()的方法可以避免这个警告弹出?
10个回答

29
显而易见的答案是要从编译器试图告诉你的内容中学习 - 你永远不应该使用 gets(),因为它是完全不安全的。相反,使用 fgets(),它允许你防止可能的缓冲区溢出。
#define BUFFER_SIZE 100
char buff[BUFFER_SIZE];
gets( buff);   // unsafe!
fgets( buff, sizeof(buff), stdin );   // safe

3
在现实生活中,你可能会想使用 sizeof buff 来代替复制缓冲区大小。 - Bastien Léonard
4
在现实生活中,您应该通过一个像BUFFSIZE这样的常量来确定缓冲区的大小,并在fgets()调用中使用它。 - anon
3
这并没有实际回答这个问题。 - Mikey T.K.

25

如果你真的想使用它。

以下是一个回答,引自:http://www.gamedev.net/community/forums/topic.asp?topic_id=523641

如果你使用的是相当新的gcc版本,你可以使用:

#pragma GCC diagnostic ignored "your option here"
例如,如果这些头文件产生“浮点比较是不安全的”错误,您将使用以下代码:
#pragma GCC diagnostic ignored "-Wfloat-equal".

不幸的是,你不能通过这种方式禁用 "-Wall"(否则就太简单了吧...),你必须手动选择由-Wall启用的每个警告选项(至少是冲突的选项)。

文档: http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas

编辑: 但对于gets警告似乎不起作用...我在我的电脑上尝试过。


3
尽管我同意不应使用gets()函数,但你是唯一一个真正回答了OP的问题。+1 - qrdl
4
这仅适用于编译器发出的诊断信息。 "gets不安全"消息来自链接器,据我所知,没有办法禁用它。 - zwol

9

使用fgets()代替gets()

char buffer[BUFSIZ];
/* gets(buffer); */
fgets(buffer,sizeof(buffer), stdin);

gets()函数不会检查缓冲区的长度,可能会写超出缓冲区范围并改变栈的内容。这就是所谓的“缓冲区溢出”。


9
我会遵从警告并替换`gets`。对于我而言,这已经很明显了:

错误

决不能使用`gets()`。因为在不提前知道数据的情况下,无法确定`gets()`将读取多少个字符,并且因为`gets()`将继续存储超过缓冲区末尾的字符,所以使用它非常危险。它被用来破坏计算机安全。请改用`fgets()`。


6

没有什么好的理由使用gets()。即使C标准也说它已经过时了!相反,使用fgets()

[编辑]

看起来警告来自链接器。使用-c进行编译时是否会收到警告?(这将禁用链接。)


5

你不应该使用gets函数,man页面建议使用fgets代替。

GCC不提供使用pragma禁用警告的功能。您必须使用各种警告选项作为编译器的标志。


这个警告是由链接器发出的。我不知道有什么方法可以禁用它。 - AProgrammer

1

提供一个安全的gets()替代方案。

在现有代码中,要替换gets(),可能不希望使用fgets(),因为该函数需要一个额外的char来保存两个函数都使用的'\n',但gets()却没有保存。以下是一种不需要更大缓冲区大小的替代方案。

每个gets(dest)都替换为:
如果dest是一个数组,则使用gets_sz(dest, sizeof dest)
如果dest是指向大小为nchar数组的指针,则使用gets_sz(dest, n)

char *gets_sz(char *dest, size_t size) {
    if (size <= 1) {
        if (size <= 0 || feof(stdin)) {
            return NULL;
        }
    }
    size--;
    size_t i;
    for (i = 0; i < size; i++) {
        int ch = getchar();
        if (ch == EOF) {
            if (i == 0)
                return NULL;
            break;
        }
        if (ch == '\n')
            break;
        dest[i] = (char) ch;
    }
    dest[i] = 0;
    return dest;
}

1

-fno-stack-protector 是一个选项,它允许使用 gets() 函数,尽管它非常不安全。

-Wno-deprecated-declarations 关闭了过时声明的警告。

以下是使用 gets() 进行编译的示例。

gcc myprogram.c -o myprogram -fno-stack-protector -Wno-deprecated-declarations

我同意所有认为这是完全不安全的人,因为它将允许程序溢出缓冲区。这可能非常危险,因此已被弃用,而推荐使用fgets。

然而,如果你正在学习安全课程,能够编写一个小测试程序来玩弄缓冲区溢出和堆栈溢出的概念非常有帮助。


我认为安全教育绝对是每个人强烈反对的唯一例外。无论如何,现在C11已经从库中删除了gets,即使这样也不起作用了。 - Deebster

0

如果你真的想使用它,请尝试使用标志-fsyntax-only

gcc网站上的手册说:

-fsyntax-only

Check the code for syntax errors, but don't do anything beyond that.

-4

与普遍观点相反,不是所有程序员都同样地疏忽他们所写的内容。在 C90 中,gets() 总是标准的,并且出于多个良好的原因被放入库中。如果适当使用,例如在程序示例、文档、单元测试脚手架、家庭作业等方面,它并不比任何其他字符串函数更加"危险"。

更重要的是,gets() 以一种 fgets() 永远不会做到的方式增强了可读性。而且一个人从不必打断思路去查看参数的顺序。

以下解决方法使用我的另一个喜爱函数来移除换行符。

 #define gets GET_LOST
 #include "stdio.h"
 #undef gets

 #include "limits.h"

 char *gets(char *s)
 {
    return strtok(fgets(s, INT_MAX, stdin), "\n");
 }

10
谁会用他们的名字、电话号码和日期签署 SO 的答案? - bgw
如果用户输入仅包含 '\n',则此例程返回 NULL。原始的 gets() 返回 "" - chux - Reinstate Monica

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