web-dev-qa-db-fra.com

Fonctions Strings de retour, bon style?

Dans mes programmes C, j'ai souvent besoin d'un moyen de faire une représentation à chaîne de mes adtes. Même si je n'ai pas besoin d'imprimer la chaîne à l'écran de quelque manière que ce soit, il est prêt à avoir une telle méthode de débogage. Donc, ce type de fonction vient 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 de la chaîne à revenir.

Alternative 1: stocker la chaîne de retour dans une matrice de caractère statique dans la fonction. Je n'ai pas besoin de penser beaucoup, sauf que la chaîne est écrasée à chaque appel. Qui peut être un problème à certaines occasions.

Alternative 2: allouer la chaîne sur le tas avec malloc à l'intérieur de la fonction. Vraiment soigné depuis que je n'aurai pas besoin de penser à la taille d'un tampon ou de l'écrasement. Cependant, je dois me rappeler de libérer () la chaîne lorsque vous avez terminé, puis j'ai également besoin d'attribuer à une variable temporaire de telle sorte que je puisse libérer. Et puis la répartition des tas est vraiment beaucoup plus lente que la répartition de la pile, soit donc un goulot d'étranglement si cela est répété dans une boucle.

Alternative 3: Passez le pointeur sur 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 devrais-je avoir d'abord et durer? (en fait, six possibilités)

Alors, que devrais-je préférer? Pourquoi? Y a-t-il une sorte de norme non écrite chez les développeurs C?

Les méthodes que j'ai vues les plus sont 2 et 3.

Le tampon fourni par l'utilisateur est en fait assez simple à utiliser:

char[128] buffer;
mytype_to_string(mt, buffer, 128);

Bien que la plupart des implémentations renvoient la quantité de tampon utilisée.

L'option 2 sera plus lente et est dangereuse lorsque vous utilisez des bibliothèques liées dynamiquement dans lesquelles ils peuvent utiliser différents travaux (et différents tas). Donc, vous ne pouvez pas libérer de ce qui a été malaxé dans une autre bibliothèque. Cela nécessite alors une fonction free_string(char*) une fonction pour y faire face.

11
ratchet freak

En plus de la réponse excellente de @ RatchetFreak, je voudrais souligner que la variante n ° 3 suit un paradigme/modèle similaire en tant que fonctions de la bibliothèque C standard C.

Par exemple, strncpy.

char * strncpy ( char * destination, const char * source, size_t num );

Suite au même paradigme aiderait à réduire la charge cognitive des nouveaux développeurs (ou même de votre avenir) lorsqu'ils doivent utiliser votre fonction.

La seule différence avec ce que vous avez dans votre message serait que l'argument destination dans les bibliothèques C a tendance à figurer en premier dans la liste des arguments. Donc:

char * mytype_to_string( char *buf, const mytype_t *mt, size_t buflen ); 
0
John Go-Soco

idée de design supplémentaire pour #

Dans la mesure du possible, fournissez également la taille maximale requise pour mytype dans le même fichier .h comme mytype_to_string().

#define MYTYPE_TO_STRING_SIZE 256

Maintenant, l'utilisateur peut coder en conséquence.

char buf[MYTYPE_TO_STRING_SIZE];
puts(mytype_to_string(mt, buf, sizeof buf));

commande

La taille des tableaux, lorsque d'abord, permet aux types de VLA.

char * mytype_to_string( const mytype_t *mt, size_t bufsize, char *buf[bufsize]); 

Pas si important avec une seule dimension, mais utile avec 2 ou plus.

void matrix(size_t row, size_t col, double matrix[row][col]);

Je me souviens de lire avoir la taille d'abord est un idiome préféré dans le prochain C. Besoin de trouver cette référence ....