Libérer un int * affecté à un char * (alloué par `malloc`) appelle-t-il le comportement indéfini?

Le titre peut être déroutant. Supposons que str soit un pointeur atsortingbué par malloc . ptr , de type int* , lui est atsortingbué et est libéré comme le montre l’extrait de code ci-dessous:

 char* str = malloc(64); int* ptr = str; free(ptr); 

J’ai essayé de comstackr le code ci-dessus. Cela donne juste un avertissement:

 source_file.c: In function 'main': source_file.c:10:16: warning: initialization from incompatible pointer type int* ptr = str; ^ 

Le code ci-dessus appelle-t-il le comportement non défini?
L’extrait de code ci-dessus libère-t-il la mémoire allouée par malloc pour str ?

    Le code ci-dessus appelle-t-il le comportement non défini?

    Ça dépend.

    A partir de la version préliminaire C11 6.3.2.3/7

    Un pointeur sur un type d’object peut être converti en un pointeur sur un type d’object différent. Si le pointeur résultant n’est pas correctement aligné) pour le type référencé, le comportement est indéfini.

    Comme l’alignement d’un caractère peut être différent de celui d’un int , ce qui est probablement moins ressortingctif, l’atsortingbution d’un caractère char * pc à un int * pi peut conduire à un mauvais alignement de pi .

    Cependant, pour l’exemple spécifique donné par le PO:

     char * pc = malloc(64); int * pi = pc; 

    le comportement serait défini, car (voir le commentaire de Alter Mann malloc() est garanti que malloc() retournera un bloc de mémoire correctement aligné.

    À partir de l’ébauche C11 7.22.3

    Le pointeur renvoyé [par alignés, calloc, malloc et realloc] si l’allocation réussit est correctement aligné de sorte qu’il puisse être affecté à un pointeur sur tout type d’object avec une exigence d’alignement fondamentale …

    Voici un exemple de comportement indéfini dû à un désalignement:

     char * pc = malloc(64); int * pi = pc + 1; 

    L’extrait de code ci-dessus libère-t-il la mémoire allouée par malloc pour str?

    Dans le cas où l’assignation précédente aurait introduit un comportement indéfini, cette question est sans importance, car tout pourrait arriver si UB a déjà été invoqué.

    Si l’atsortingbution précédente n’avait pas invoqué UB, l’appel à free() désaffecterait parfaitement le bloc de mémoire référencé, car il reconvertirait la valeur du pointeur de int * à void * , fournie à l’origine par malloc() , est bien défini.

    A partir de la version préliminaire C11 du 6.3.2.3/7 (suite):

    Sinon, lorsqu’il sera reconverti, le résultat sera comparable au pointeur original.

    et

    A partir de la version préliminaire C11 du 6.3.2.3/1:

    Un pointeur à annuler peut être converti en ou à partir d’un pointeur en n’importe quel type d’object. Un pointeur sur n’importe quel type d’object peut être converti en un pointeur à annuler et inverser; le résultat doit être égal au pointeur d’origine

    Non, cela n’invoque pas un comportement indéfini . L’avertissement concerne simplement les types incompatibles que vous pouvez lancer.

     char* str = malloc(64); int* ptr = (int*) str; free(ptr); 

    free prend un pointeur vide et ce qui précède ne pose aucun problème. Toutefois, l’utilisation du résultat d’une telle valeur peut invoquer un comportement non défini en raison de l’alignement du type int et du type char. En tant que telle, la conversion de char* en int* ne conduit pas à undefined.

    Le code ci-dessus appelle-t-il le comportement non défini?

    Non.

    L’extrait de code ci-dessus libère-t-il la mémoire allouée par malloc pour str?

    Oui.

    Juste pour clarifier, quelques notes sur UB concernant l’allocation dynamic:

    La mémoire renvoyée par malloc est alignée pour prendre toute valeur possible. Cette mémoire n’a pas de type déclaré et son type effectif est défini via le stockage.

    Si tu fais

     *ptr = 42; 

    la première sizeof (int) octets du bloc de mémoire sera maintenant du type int et ne pourra être lue que telle, c’est-à-dire

     float val = *(float *)ptr; 

    sera UB.

    cependant,

     *(float *)ptr = 42.0; 

    serait légal car il rétablit le type effectif, rendant à présent à son tour la lecture via *ptr invalide.

    De plus, il est toujours légal d’accéder à n’importe quel object avec des pointeurs de type char ou unsigned char .

    Il peut invoquer UB en fonction de l’endianité, des alignements ou de la conversion de caractères int vs char lors de l’access. Quand vous faites malloc, tout ce que cela fait est de retourner un void* qui peut être de n’importe quel type de données (et nécessiter dans certains cas une transtypage). Cela ne fait aucune différence si vous mettez un pointeur dans char * à int *, mais il y aurait une différence dans les unités d’access, c’est-à-dire que dans le cas d’une entrée de 4 octets à la fois ou d’un caractère à la fois. Donc, le code de votre question n’invoque pas UB, mais des access mémoire peuvent le faire.

    En ce qui concerne la deuxième question, si vous appelez free sur ptr , la mémoire pointée par str également libérée. Maintenant, str serait un pointeur qui pendait.