隐式声明如何工作

sak*_*ura 3 c declaration

当您不包含和使用malloc时,我们会收到隐式声明警告.

"警告:内置函数'malloc'的不兼容的隐式声明"

此警告是由于编译器假定malloc定义为int malloc(size)void* malloc(size).

但它是如何知道的void* malloc(size)?我们没有在头文件中包含任何内容.那么如何将它与未包含的内容进行比较呢?

之后,我的代码如何工作?它如何找到正确的malloc定义并使用它?

是否有扫描函数定义的序列顺序?

Fil*_*ves 5

当您调用一个f从未定义过的函数时,会发生这样的隐式声明:

int f();
Run Code Online (Sandbox Code Playgroud)

请注意,您仍然可以传递参数f,因为它未被声明int f(void);(这是为了向后兼容K&R C).

因此,编译器不"知道"malloc接收到一个size参数,实际上你可以将它传递给你想要的,它并不关心.

所以,代码工作的纯粹事实就是纯粹的运气.在malloc的情况下,如果代码有效,它只是意味着整数的大小与指针的大小相同 - 不多也不少 - 所以,你仍然可以调用malloc并将其结果赋值给指针,因为没有比特被修剪/丢失.

在编译发生后,在链接阶段找到真正的函数.到目前为止,您的代码已经使用错误的函数原型进行编译.当然,如果链接器无法在其路径中的任何位置找到该函数,则会报告错误并中止所有内容.

对于malloc和其他标准库函数的情况,可能有内置函数来提高性能.gcc甚至可以选择禁用内置函数(-fno-builtin-fno-builtin-function).来自gcc手册页:

GCC通常会生成特殊代码来更有效地处理某些内置函数; 例如,对"alloca"的调用可能会成为直接调整堆栈的单个指令,而对"memcpy"的调用可能会成为内联复制循环.生成的代码通常更小更快,但由于函数调用不再显示,因此您无法在这些调用上设置断点,也无法通过链接到不同的库来更改函数的行为.此外,当函数被识别为内置函数时,GCC可以使用有关该函数的信息来警告调用该函数的问题,或生成更高效的代码,即使结果代码仍包含对该函数的调用.

因此,在malloc的特定情况下,这就是编译器"知道"其通常签名的方式.尝试使用gcc编译此代码:

int main(void) {
    char *a = malloc(12, 13, 14, 15);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

您将看到它将因编译错误而中止:

test.c:3: error: too many arguments to function `malloc'
Run Code Online (Sandbox Code Playgroud)

如果使用该选项-fnobuiltin,则错误消失且警告不同:

test.c:3: warning: implicit declaration of function `malloc'
Run Code Online (Sandbox Code Playgroud)

这与您每次使用之前未定义的常规函数​​时获得的警告相同,因为现在编译器忽略了他对这些函数的"了解".此示例使用gcc,但其他编译器将具有类似的行为.