当我malloc
在C程序中使用时,我收到警告:
warning: incompatible implicit declaration of built-in function 'malloc' [enabled by default]
Run Code Online (Sandbox Code Playgroud)
然后我可以包括<malloc.h>
或<stdlib.h>
摆脱warning
它虽然它没有它也可以工作.
所以我想知道,gcc
当我不包含任何内容时,这些标题之间有什么区别?
(我使用ubuntu 12.04 64-bit
同gcc 4.6.3
)
Bas*_*tch 50
该<malloc.h>
标头已被弃用(和相当的Linux具体而言,在其上它定义非标准类似功能mallinfo(3) ).使用<stdlib.h>
如果您只是需要的malloc(3)和相关标准的功能(例如free
,calloc
,realloc
...).请注意,它<stdlib.h>
是由C89(及更高版本)标准定义的,但不是<malloc.h>
看看/usr/include/malloc.h
你会发现一些非标准功能(例如malloc_stats(3)等......) - 除了malloc
....
并且gcc
不要链接头文件,而是库.阅读Levine关于接头和装载机的书籍.
如果你不包含任何标题(并且不明确声明malloc
自己,这可能是一个坏主意),malloc
则隐式声明为返回某个int
值(这是错误的).我邀请你在使用它时至少传递-Wall
旗帜gcc
.
您也可以传递-v
以gcc
了解所涉及的实际程序:cc1
编译器是否正确(生成汇编代码),as
汇编器,ld
链接器和collect2是调用链接器的内部实用程序.
stdlib.h是一个标准的C头,它声明了malloc(),calloc(),free()函数.这是您应该包含的标题.
malloc.h是一个非标准的头文件,可在许多系统中找到,它通常定义特定于该平台使用的malloc实现的附加功能.
如果你不包含任何这些,那么没有默认值,但是如果你在没有事先声明malloc函数的情况下调用malloc(),C将假设函数原型是int malloc();
,这通常是错误的.除了头文件之外,C编译器通常链接到标准库,例如Linux上的glibc,其中malloc的实现驻留在其中.
请注意,头文件和库之间存在差异.头文件声明了一些东西,比如结构和函数原型.库包含实现,编译代码.您链接到库,并#include头文件.
标题声明了不同的函数集,但都是前向声明的malloc
.
如果你不包括其中任何一个,那么你没有原型malloc
,因此警告.但无论如何都要链接相同的函数,因为只有一个malloc
函数.它只是在两个地方向前宣布.前向声明不是为了帮助链接malloc
函数,它们就在那里,以便编译器可以在调用周围发出正确的代码,指定参数并读取返回值.
请注意,这<malloc.h>
不是标准包含.我认为stdlib.h
永远不会包括malloc.h
海湾合作委员会,但你可以想象它可能因为这是提供必要声明的一种方式.
其他人已经讨论了 <malloc.h> 和 <stdlib.h> 之间的差异
\n至于两者都不包含时的警告,这是 C 函数如何工作的定义。没有原型的函数(当您没有声明自己的原型并且不包含带有原型的标头时所拥有的函数)将被视为具有返回类型int
和未指定参数列表的函数。
编译器将执行默认提升(例如,float 到 double 等)并调用该函数。如果函数使用的参数数量与传递的参数数量不同,或者默认提升后的参数类型与函数的实现不兼容,则这是未定义的行为。
\n参见 ISO 9899:1999 (C99) \xc2\xa76.5.2.2、\xc2\xb6 6:
\n\n\n如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并且具有类型的参数
\nfloat
将提升为double
。这些称为默认参数促销。如果参数的数量不等于参数的数量,则行为未定义。如果函数是使用包含原型的类型定义的,并且原型以省略号 (, ...) 结尾,或者提升后的参数类型与参数类型不兼容,则行为未定义。如果函数定义的类型不包含原型,并且提升后的实参类型与提升后的参数类型不兼容,则行为未定义,但以下情况除外:\n
\n- 一种提升类型是有符号整数类型,另一种提升类型是相应的无符号整数类型,并且该值可以用两种类型表示;
\n- 这两种类型都是指向字符类型或 的限定或非限定版本的指针
\nvoid
。
在没有原型的情况下调用的情况下malloc()
,这可能会非常糟糕。 malloc()
接受一个size_t
参数并返回一个void *
指针。如果整数参数的默认提升结果产生的整数大小与 不同size_t
,则将出现未定义的行为。如果int
大小不同void *
(例如,在 64 位系统上,通常int
是 32 位,void *
将来会是 64 位),则返回的指针将会混乱。