La signature de char est-elle un problème d’interface?

Supposons que j’ai une fonction

void foo(char *) 

qui, en interne, doit traiter son entrée comme un bloc d’octets terminés par NUL (par exemple, c’est une fonction de hachage sur les chaînes). Je pourrais lancer l’argument sur unsigned char* dans la fonction. Je pourrais aussi changer la déclaration en

 void foo(unsigned char *) 

Maintenant, étant donné que char , char signed char et unsigned char sont trois types différents , cela constituerait-il un changement d’interface, quelle que soit la définition raisonnable du terme “interface” en C?

(Cette question a pour but de régler une discussion soulevée par une autre question. J’ai mes opinions, mais je n’accepterai pas de réponse tant que l’une des voix n’aura pas été désignée “gagnante” par le vote des autres.)

    Selon ISO / IEC 9899: TC3,

    • appeler une fonction par une expression de type incompatible est un comportement indéfini (6.5.2.2 §9)
    • les types de fonctions compatibles doivent avoir des types de parameters compatibles (6.7.5.3 §15)
    • les types de pointeurs compatibles doivent pointer vers les types compatibles (6.7.5.1 §2)
    • char , caractère signed char et caractère unsigned char sont des types de base différents (6.2.5 §14) et sont donc incompatibles (6.2.7 §1), ce qui est également mentionné explicitement dans la note de bas de page 35 à la page 35

    Alors oui, il s’agit clairement d’un changement d’interface de programmation.

    Toutefois, étant donné que char * , signed char * et unsigned char * auront des représentations et des exigences d’alignement identiques dans toute implémentation rationnelle du langage C, l’interface binary restra inchangée.

    Oui, ça l’est. Le code client précédemment compilé ne sera plus compilé (ou de toute façon est susceptible de générer de nouveaux avertissements), il s’agit donc d’un changement radical.

    Je choisis “C – aucune de ces réponses.”

    Bien que ce ne soit pas une réponse directe à la question que vous avez réellement posée, la bonne solution à la situation me semble assez simple et évidente: vous ne devriez vraiment pas utiliser ce qui précède.

    Au moins, IMO, vous avez une très bonne raison de faire autrement, votre fonction devrait accepter un void * ou (de préférence) un void const * . Ce que vous recherchez est essentiellement un pointeur opaque, et c’est exactement ce que void * fournit. L’utilisateur n’a pas besoin de connaître les éléments internes de votre implémentation, et comme tout autre type de pointeur convertira implicitement en void * , c’est l’une des rares possibilités qui ne casse pas non plus le code existant.

    Un caractère * convertit-il implicitement en un caractère non signé *?

    • Oui, vous n’avez pas cassé votre interface
    • Non – vous avez une implémentation perdue
      détails.

    Non ce n’est pas. Toute modification du code client est sortingviale (en particulier si c’est juste pour éviter un avertissement) et, dans la pratique, dans pratiquement toute implémentation en C, vous constaterez que vous n’avez même pas besoin de recomstackr, car les pointeurs sur char* et les unsigned char* sera passé exactement de la même manière dans la convention d’appel.