【问题标题】:Compiler gives - warning C4013: 'getche' undefined; assuming extern returning int编译器给出 - 警告 C4013: 'getche' undefined;假设 extern 返回 int
【发布时间】:2015-01-27 12:42:45
【问题描述】:

我正在使用 Visual Studio 进行代码开发以及何时使用该函数

getche()

编译器给了我这个警告

 warning C4013: 'getche' undefined; assuming extern returning int

但是 getche() 函数按预期工作,为什么编译器会显示这样的警告,我该如何消除这个警告?

【问题讨论】:

    标签: c getch


    【解决方案1】:

    正如您的编译器告诉您的,getche 尚未定义。

    通常,您会包含一个标题(例如#include <conio.h>),它定义的函数有点类似于:

    int getche(void);
    

    C 语言有一条规则允许使用以前未定义的函数。假定这些函数采用它们传递的确切参数类型(无,所以void)并返回int。由于此功能(即 evil™)以及 getche 确实由于您的链接器设置而被链接的事实,您的程序实际上可以正常工作。

    请注意,getche 已被弃用,您应该改用 _getche

    【讨论】:

    • 谢谢,这解决了这个问题(顺便说一下,在windows中我们必须给我们 _getche();
    • 谢谢。对初学者很实用。
    【解决方案2】:

    我想补充一点:纠正此类错误并非易事,因为缺少声明可能会导致更多错误。

    以简单的调用foo(4) 为例。假设没有关于此调用如何工作的更多信息。编译器能够从这样的调用中读取什么?

    1. 参数数量(非常明显)。
    2. 参数类型(4 通常扩展为 4 字节值,4LL 在 64 位机器 (gcc) 上扩展为 8 字节值)。
    3. 参数应该被压入堆栈的顺序(调用约定 - 大多数情况下是 C 约定,但这取决于您的编译器设置)。

    编译器无法从该调用中读取什么:

    1. 调用返回什么样的值。

    没错。因为foo 可能在另一个模块中定义,甚至在系统库中。没有声明的符号foo 对编译器来说是完全未知的。因为它只是编译你的代码,但它不负责符号的链接(我说符号是因为它可以包含变量函数)。

    现在,编译器必须做什么

    1. 它需要为每个调用生成指令。根据调用约定,这些指令可能会有很大差异。例如,对于cdecl调用者 必须将参数压入堆栈,并且在每次调用函数之前。对于stdcall被调用者必须清理堆栈。

    2. 它需要知道参数的类型。好吧,实际上它并不关心类型,而是对象占用的大小。一个 20 字节的结构对象在堆栈上需要 20 个字节,不是吗?而且每个参数都需要放在上面(按值调用)。

    3. 而且它需要在栈上为函数的返回值预留足够的内存。因为:无论函数要返回什么,都存储在该内存中。如果函数返回一个 20 字节的结构对象,它需要 20 个字节。到目前为止,一切顺利。

    现在,除了返回值之外的任何内容都可以从调用中读取 - 返回值必须由声明提供。如果未提供此声明,编译器将仅在堆栈中保留 sizeof(int)(大部分时间为 4 个字节)作为返回值,并将其余部分留给链接器。

    链接器看到符号foo(4 bytes) 并将开始寻找foo(4 bytes) 的任何对应定义。如果它发现了(比如,在你的另一个模块中,或者在你系统的 libc 中,或者作为系统调用包装器),那么链接器就是内容,它将创建可执行文件。

    一切都很好,不是吗?嗯,不,不是。

    例如,GNU 系统上提供了一个名为memmem 的函数,该函数在定义_GNU_SOURCE 时被激活,然后包含string.h。如果您在包含该函数之前没有碰巧定义_GNU_SOURCE,则memmem 的声明将被跳过,编译器将无法确定该函数的返回值并自动假定为4 个字节。当您在 32 位系统上时,这是“可以的”——但是如果您的程序被编译为 64 位可执行文件并且您传递给 memmem 的 haystack 是一个 64 位指针,它指向 0xFFFFFFFF 上方,即高 32 位你的指针被删除了(好像你已经写了return (pointer&0xFFFFFFFFULL);)。而这个新指针可以指向我所说的“坏涅槃”,与“好涅槃”相对应。 “好涅槃”是NULL,大家可以看出这个指针不应该被解引用。对于指向“坏涅槃”的指针,要做到这一点更加困难。

    链接器不会对您的memmem 调用有任何问题,因为我们的系统库仍然知道该函数。不求也能得到,用了就会出卖你。

    因此请记住:即使您的编译器需要声明,您仍然希望提供一个。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-08
      • 1970-01-01
      • 2017-08-17
      • 1970-01-01
      • 1970-01-01
      • 2018-03-18
      • 1970-01-01
      • 2010-11-09
      相关资源
      最近更新 更多