web-dev-qa-db-fra.com

différence entre <stdlib.h> et <malloc.h>

Lorsque j'utilise malloc dans un programme C, je reçois un avertissement:

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

Je peux ensuite inclure <malloc.h> ou <stdlib.h> pour se débarrasser de warning bien qu'il fonctionne également sans.

Je me demandais donc quelle est la différence entre ces en-têtes et lequel fait des liens gcc quand je n'inclus rien?

(J'utilise ubuntu 12.04 64-bit avec gcc 4.6.3)

40
none

Le <malloc.h> l'en-tête est obsolète (et assez spécifique à Linux, sur lequel il définit des fonctions non standard comme mallinfo (3) ) . Utilisation <stdlib.h> à la place si vous avez simplement besoin de malloc (3) et des fonctions standard associées (par exemple free, calloc, realloc ....). Remarquerez que <stdlib.h> est défini par les normes C89 (et ultérieures), mais pas <malloc.h>

Regardez dans /usr/include/malloc.h vous y trouverez des fonctions non standard (par exemple malloc_stats (3) , etc ...) - en plus de malloc....

Et gcc ne lie pas les fichiers d'en-tête, mais les bibliothèques. Lisez le livre de Levine sur linkers & loaders pour en savoir plus.

Si vous n'incluez aucun en-tête (et que vous ne déclarez pas explicitement malloc vous-même, ce qui serait une mauvaise idée), malloc est implicitement déclaré comme renvoyant une valeur int (qui est faux). Je vous invite à passer au moins le -Wall drapeau à gcc lors de son utilisation.

Vous pourriez également passer -v à gcc pour comprendre les programmes réels impliqués: cc1 est le compilateur proprement dit (produisant le code assembleur), as l'assembleur, ld l'éditeur de liens et collect2 un utilitaire interne qui appelle l'éditeur de liens.

49

stdlib.h est un en-tête C standard qui déclare entre autres les fonctions malloc (), calloc (), free (). C'est l'en-tête que vous devez inclure.

malloc.h est un en-tête non standard, trouvé sur de nombreux systèmes où il définit souvent des fonctions supplémentaires spécifiques à l'implémentation malloc utilisée par cette plateforme.

Si vous n'incluez aucun de ces éléments, il n'y a pas de valeur par défaut, cependant si vous appelez malloc () sans déclaration préalable de la fonction malloc, C supposera que le prototype de la fonction est int malloc();, ce qui est souvent faux. En plus des en-têtes, les compilateurs C sont généralement liés à une bibliothèque standard, par ex. glibc sous Linux, où réside l'implémentation de malloc.

Notez qu'il existe une différence entre les fichiers d'en-tête et les bibliothèques. Les fichiers d'en-tête déclarent des choses, comme des structures et des prototypes de fonctions. Les bibliothèques contiennent l'implémentation, le code compilé. Vous créez un lien vers la bibliothèque et vous #incluez les fichiers d'en-tête.

9
nos

Les en-têtes déclarent différents ensembles de fonctions, mais les deux déclarent en avant malloc.

Si vous n'incluez aucun d'entre eux, vous n'avez pas de prototype pour malloc, d'où l'avertissement. Mais vous liez malgré tout la même fonction, car il n'y a qu'une seule fonction malloc. C'est juste déclaré à deux reprises. Les déclarations directes ne sont pas là pour aider à établir un lien avec la fonction malloc, elles sont là pour que le compilateur puisse émettre le code correct autour de l'appel, pour spécifier les arguments et lire la valeur de retour.

Notez que <malloc.h> n'est pas une inclusion standard. Je ne pense pas stdlib.h inclut toujours malloc.h sur GCC, mais vous pouvez imaginer que ce pourrait être le cas puisque c'est une façon de fournir la déclaration nécessaire.

6
Steve Jessop

<malloc.h> N'est pas un en-tête standard et n'est donc pas portable. La norme met malloc() et al. dans <stdlib.h>.

3
aib

D'autres ont déjà discuté des différences entre <malloc.h> et <stdlib.h>

Quant à l'avertissement quand aucun n'est inclus, c'est la définition du fonctionnement des fonctions C. Une fonction sans prototype (qui est ce que vous avez lorsque vous ne déclarez pas le vôtre et n'incluez pas d'en-tête avec un) est traitée comme une fonction avec un type de retour int et un non spécifié liste d'arguments.

Le compilateur effectuera des promotions par défaut (par exemple, float to double et autres) et la fonction est appelée. Si le nombre d'arguments utilisés par la fonction est différent du nombre passé, ou si les types d'arguments après les promotions par défaut ne sont pas compatibles avec l'implémentation de la fonction, il s'agit d'un comportement non défini.

Voir ISO 9899: 1999 (C99) §6.5.2.2, ¶ 6:

Si l'expression qui dénote la fonction appelée a un type qui n'inclut pas de prototype, les promotions entières sont effectuées sur chaque argument et les arguments qui ont le type float sont promus en double. Ceux-ci sont appelés promotions d'argument par défaut. Si le nombre d'arguments n'est pas égal au nombre de paramètres, le comportement n'est pas défini. Si la fonction est définie avec un type qui inclut un prototype et que le prototype se termine par des points de suspension (, ...) ou que les types d'arguments après promotion ne sont pas compatibles avec les types de paramètres, le comportement n'est pas défini. Si la fonction est définie avec un type qui n'inclut pas de prototype et que les types des arguments après promotion ne sont pas compatibles avec ceux des paramètres après promotion, le comportement n'est pas défini, sauf dans les cas suivants:

  • un type promu est un type entier signé, l'autre type promu est le type entier non signé correspondant, et la valeur est représentable dans les deux types;
  • les deux types sont des pointeurs vers des versions qualifiées ou non qualifiées d'un type de caractère ou void.

Dans le cas de l'appel de malloc() sans prototype, cela peut être très mauvais. malloc() accepte un size_t argument et renvoie un void * pointeur. Si le résultat de la promotion par défaut de votre argument entier produit un entier de taille différente de size_t, vous aurez un comportement indéfini. Et si int est d'une taille différente de void * (par exemple, sur les systèmes 64 bits, où int est souvent 32 bits et void * sera de 64 bits,) le pointeur renvoyé sera gâché.

2
David C.

Pour apprendre la différence, vous devriez lire leur contenu par vous-même.

Par défaut, gcc ne lit ni l'un ni l'autre.

Lorsque vous les lirez, vous verrez qu'ils déclarent malloc différemment.

1
bmargulies