Dans mes programmes C, j'ai souvent besoin d'un moyen de faire une représentation sous forme de chaîne de mes ADT. Même si je n'ai pas besoin d'imprimer la chaîne à l'écran de quelque manière que ce soit, il est intéressant d'avoir une telle méthode de débogage. Donc, ce genre de fonction revient souvent.
char * mytype_to_string( const mytype_t *t );
En fait, je me rends compte que j'ai (au moins) trois options ici pour gérer la mémoire pour la chaîne à retourner.
Alternative 1: Stockage de la chaîne de retour dans un tableau de caractères statiques dans la fonction. Je n'ai pas besoin de beaucoup de réflexion, sauf que la chaîne est écrasée à chaque appel. Ce qui peut être un problème à certaines occasions.
Alternative 2: allouez la chaîne sur le tas avec malloc à l'intérieur de la fonction. Vraiment bien puisque je n'aurai alors pas besoin de penser à la taille d'un tampon ou à l'écrasement. Cependant, je dois me rappeler de libérer () la chaîne une fois terminé, puis je dois également attribuer à une variable temporaire que je peux libérer. et puis l'allocation de tas est vraiment beaucoup plus lente que l'allocation de pile, donc soyez un goulot d'étranglement si cela se répète dans une boucle.
Alternative 3: passez le pointeur vers un tampon et laissez l'appelant allouer ce tampon. Comme:
char * mytype_to_string( const mytype_t *mt, char *buf, size_t buflen );
Cela apporte plus d'efforts à l'appelant. Je remarque également que cette alternative me donne une autre option sur l'ordre des arguments. Quel argument dois-je avoir en premier et en dernier? (en fait six possibilités)
Alors, que dois-je préférer? Pourquoi? Existe-t-il une sorte de standard non écrit parmi les développeurs C?
la source
sysctlbyname
sous OS X et iOSRéponses:
Les méthodes que j'ai vues le plus sont 2 et 3.
Le tampon fourni par l'utilisateur est en fait assez simple à utiliser:
Bien que la plupart des implémentations renvoient la quantité de tampon utilisée.
L'option 2 sera plus lente et est dangereuse lors de l'utilisation de bibliothèques liées dynamiquement où elles peuvent utiliser des temps d'exécution différents (et des tas différents). Vous ne pouvez donc pas libérer ce qui a été mallocé dans une autre bibliothèque. Cela nécessite alors une
free_string(char*)
fonction pour y faire face.la source
printf("MyType: %s\n", mytype_to_string( mt, buf, sizeof(buf));
et donc je n'aime pas retourner la longueur utilisée mais plutôt le pointeur sur la chaîne. Le commentaire de bibliothèque dynamique est vraiment important.sizeof(buffer) - 1
pour satisfaire le\0
terminateur?snprintf
utilisé par la chaîne de sécurité dans la bibliothèque standard .Idée de conception supplémentaire pour # 3
Lorsque cela est possible, indiquez également la taille maximale requise
mytype
dans le même fichier .h quemytype_to_string()
.L'utilisateur peut maintenant coder en conséquence.
Ordre
La taille des tableaux, lorsqu'elle est d'abord, permet les types VLA.
Pas si important avec une seule dimension, mais utile avec 2 ou plus.
Je me souviens que la lecture ayant la taille en premier est un idiome préféré dans le prochain C. Besoin de trouver cette référence ....
la source
En complément de l'excellente réponse de @ ratchetfreak, je voudrais souligner que l'alternative # 3 suit un paradigme / modèle similaire à celui des fonctions de bibliothèque C standard.
Par exemple
strncpy
,.Suivre le même paradigme aiderait à réduire la charge cognitive pour les nouveaux développeurs (ou même votre futur soi) lorsqu'ils ont besoin d'utiliser votre fonction.
La seule différence avec ce que vous avez dans votre article serait que l'
destination
argument dans les bibliothèques C a tendance à être répertorié en premier dans la liste des arguments. Donc:la source
Outre le fait que ce que vous proposez de faire est une mauvaise odeur de code, l'alternative 3 me semble la meilleure. Je pense aussi comme @ gnasher729 que vous utilisez la mauvaise langue.
la source
Pour être honnête, vous souhaiterez peut-être passer à une autre langue où le retour d'une chaîne n'est pas une opération complexe, exigeante en travail et sujette aux erreurs.
Vous pouvez envisager C ++ ou Objective-C où vous pouvez laisser 99% de votre code inchangé.
la source