<stdlib.h>和<malloc.h>之间的区别

51

在C程序中使用malloc时,我收到一个警告:

warning: incompatible implicit declaration of built-in function 'malloc' [enabled by default]

我可以包含 <malloc.h><stdlib.h> 来消除 warning,尽管没有这样做也能正常工作。

因此,我想知道这些头文件之间的区别,当我没有包含任何内容时,gcc 链接哪个头文件?

(我使用 ubuntu 12.04 64位gcc 4.6.3

6个回答

59
标头文件<malloc.h>已被弃用(并且相当于Linux特定的,其中定义了一些非标准函数,如mallinfo(3))。如果您只需要malloc(3)和相关标准函数(例如freecallocrealloc等),请改用<stdlib.h>。注意<stdlib.h>C89(及更高版本)标准定义,但不包括<malloc.h>

查看/usr/include/malloc.h,您会发现一些非标准函数(例如malloc_stats(3)等...)-除了malloc之外....

gcc不会链接头文件,而是链接库。了解有关链接器和加载程序的Levine书籍的更多信息。

如果您没有包含任何标头文件(并且没有明确声明malloc自己,这是一个坏主意),malloc会被隐式声明为返回某个int值(这是错误的)。当使用gcc时,我建议您至少传递-Wall标志。

你也可以向gcc传递-v参数,以了解实际涉及到的程序: cc1是编译器本身(生成汇编代码),as是汇编器,ld是链接器,而collect2是一个内部实用工具,它调用链接器。


是的,我猜链接可能是一个错误的术语。我的意思是问当我没有包含任何头文件时,gcc如何找到malloc函数? - none
2
连接是一个好术语。但连接器不知道 C 函数的签名,只知道它们的名称。只有编译器本身(由“gcc”启动的“cc1”)关心函数的类型签名。 - Basile Starynkevitch
"<malloc.h>头文件已经被弃用了..." - 我刚刚在一个安装有GCC 4.9的Debian 8.2系统上不得不包含它。显然,它还是很活跃的... - jww
3
<malloc.h>可以同时存在两种状态:存活(存在的头文件)和弃用(建议不再使用)。 - Basile Starynkevitch
1
令人惊讶的是,memalign() 是在 malloc.h 中声明的非标准函数之一。它不是 C 标准库的一部分。 - Joel Cunningham
2
@JoelCunningham:这是因为posix_memalign(POSIX)和aligned_alloc(C11)是唯一标准化的名称。memalign本身已经“过时且非标准化”。 - ShadowRanger

13

stdlib.h是一个标准的C头文件,其中声明了malloc()calloc()free()等函数。这是您应该包含的头文件。

malloc.h是一个非标准的头文件,在许多系统上都可以找到它,通常定义了特定于该平台使用的malloc实现的其他函数。

如果您没有包含任何这些头文件,则没有默认设置;但是如果在没有先前声明malloc函数的情况下调用malloc(),C将假定函数原型为int malloc();,这通常是不正确的。除了这些头文件之外,C编译器通常会链接到一个标准库,例如Linux上的glibc,其中包含malloc的实现。

请注意,头文件和库之间存在差异。头文件声明结构体和函数原型等内容,而库则包含已编译的代码的实现。您需要链接库,并且需要使用#include来包含头文件。


7

这些头文件声明了不同的函数集,但两者都进行了 malloc 的前向声明。

如果您没有包含其中任何一个,则没有 malloc 的原型,因此会出现警告。但是,无论如何都会链接到相同的函数,因为只有一个 malloc 函数。它只是在两个位置进行了前向声明。这些前向声明不是为了帮助链接 malloc 函数,而是为了让编译器能够在调用周围生成正确的代码,以指定参数并读取返回值。

请注意,<malloc.h> 不是标准包含文件。我认为在 GCC 上 stdlib.h 从未包含 malloc.h,但您可以想象这可能是提供必要声明的一种方式。


只是为了明确,它没有给我一个“错误”,而是一个“警告”。程序在我不包括任何东西的情况下正常工作。 - none
1
@gokcehan:不过你应该注意这个警告。如果在作用域内调用malloc而没有原型,那么可能会出现实际的缺陷,而警告则是你的防御措施。https://dev59.com/dHRB5IYBdhLWcg3wgHWr 如果程序能够正常工作,那只是因为在这种情况下调用惯例的细节比较幸运--相同的代码在编译为其他CPU上的Linux时可能会失败。 - Steve Jessop

6
其他人已经讨论了<malloc.h>和<stdlib.h>之间的区别。
至于在没有包含任何一个头文件时出现的警告,这是C函数工作方式的定义。没有原型的函数(当您没有声明自己并且没有包含具有原型的标头文件时)被视为具有int返回类型和未指定参数列表的函数。
编译器将执行默认提升(例如将float转换为double等),并调用该函数。如果函数使用的参数数量与传递的数量不同,或者默认提升后的参数类型与函数实现不兼容,则其行为是未定义的。
请参见ISO 9899:1999(C99)§6.5.2.2,第6段:

如果表示所调用函数的表达式具有不包括原型的类型,则对每个参数执行整数提升,并将具有类型float的参数提升为double。 这些被称为默认参数晋升。 如果参数数量不等于参数数量,则行为是未定义的。 如果使用包括省略号(...)结尾的原型定义函数,或者在提升后的参数类型与参数类型不兼容的情况下定义函数,则行为是未定义的。 如果使用不包括原型的类型定义函数,并且在提升后的参数类型与参数类型不兼容,则行为是未定义的,除以下情况外:

  • 一个提升后的类型是有符号整数类型,另一个提升后的类型是相应的无符号整数类型,并且该值在两种类型中都可表示;
  • 两种类型都是指向字符类型或void的限定或未限定版本的指针。
在没有原型的情况下调用malloc()可能非常糟糕。 malloc()接受size_t参数并返回void *指针。 如果您的整数参数的默认提升结果产生与size_t大小不同的整数,则您将具有未定义的行为。 如果intvoid *(例如在64位系统上,其中int通常为32位,而void *将为64位)大小不同,则返回的指针将被破坏。

5

<malloc.h> 不是标准头文件,因此不具有可移植性。 标准将 malloc() 等函数放在 <stdlib.h> 中。


-1

要了解它们的区别,您应该亲自阅读它们的内容。

默认情况下,gcc 都不会读取它们。

当您阅读它们时,您会发现它们以不同的方式声明 malloc


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