50

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

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

然后我可以包含<malloc.h><stdlib.h>删除它,warning尽管它在没有它的情况下也可以工作。

gcc所以我想知道,当我不包含任何内容时,这些标题和链接有什么区别?

(我正在使用ubuntu 12.04 64-bitwith gcc 4.6.3

4

6 回答 6

58

<malloc.h>头已弃用(并且非常特定于 Linux,它在其上定义了诸如mallinfo(3)之类的非标准函数)。如果您只需要malloc(3)和相关的标准函数(例如, , ....) ,请改用。请注意,这是由C89(及更高版本)标准定义的,但不是<stdlib.h>freecallocrealloc<stdlib.h><malloc.h>

看看/usr/include/malloc.h你会发现有一些非标准函数(例如malloc_stats(3)等......) - 除了malloc......

并且gcc不要链接头文件,而是链接库。阅读 Levine 关于链接器和加载器的书了解更多信息。

如果您不包含任何标头(并且不明确声明malloc自己,这将是一个坏主意),malloc则隐式声明为返回某个int值(这是错误的)。我确实邀请您在使用时至少将-Wall标志传递给gcc它。

您还可以通过-v了解gcc实际涉及的程序:cc1编译器是否正确(生成汇编代码)、as汇编器、ld链接器和collect2是调用链接器的内部实用程序。

于 2012-10-19T11:31:53.707 回答
12

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

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

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

请注意,头文件和库之间存在差异。头文件声明了一些东西,比如结构和函数原型。库包含实现、编译的代码。您链接到库和#include头文件。

于 2012-10-19T11:34:49.983 回答
6

标头声明了不同的函数集,但都是 forward-declare malloc

如果您不包括其中任何一个,那么您就没有原型malloc,因此会发出警告。但是无论如何,您都链接到同一个函数,因为只有一个malloc函数。它只是在两个地方预先声明。前向声明不是为了帮助链接malloc函数,它们在那里是为了让编译器可以在调用周围发出正确的代码,指定参数并读取返回值。

请注意,这<malloc.h>不是标准包含。我不认为GCCstdlib.h包括malloc.h,但你可以想象它可能因为这是提供必要声明的一种方式。

于 2012-10-19T11:31:26.910 回答
4

<malloc.h>不是标准标头,因此不可移植。标准提出malloc()等。在<stdlib.h>.

于 2012-10-19T11:34:11.540 回答
4

其他人已经讨论过 <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,您将有未定义的行为。如果int大小不同void *(例如,在 64 位系统上,int通常是 32 位并且void *将是 64 位),则返回的指针将被弄乱。

于 2016-02-12T23:04:45.777 回答
1

要了解差异,您应该自己阅读它们的内容。

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

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

于 2012-10-19T11:30:57.050 回答