Quelle est la meilleure alternative à strncpy ()?

La fonction strncpy() ne termine pas toujours null, alors je veux savoir quelle est la meilleure alternative qui se termine toujours par null? Je veux une fonction qui si:

 strlen(src) >= n /*n is the number of characters to be copied from source*/ 

il n’y a pas besoin d’append un code supplémentaire comme ceci:

 buf[sizeof(buf)-1] = 0; 

Si la longueur de la chaîne que vous souhaitez copier est inconnue, vous pouvez utiliser snprintf ici. Cette fonction envoie une sortie formatée à str . Il agit de la même manière que sprintf() , mais n’écrit plus d’octets alloués par str . Si la chaîne résultante est plus longue que n-1 caractères, les caractères restants sont omis. Il inclut également toujours le terminateur nul \0 , sauf si la taille du tampon est 0 .

Ce serait une alternative à strncpy() ou strcpy() , si vous ne voulez vraiment pas l’utiliser. Cependant, append manuellement un terminateur nul à la fin de votre chaîne avec strcpy() est toujours une approche simple et efficace. Il est très normal en C d’append un terminateur nul à la fin de toute chaîne traitée.

Voici un exemple de base d’utilisation de sprintf() :

 #include  #include  #include  #define SIZE 1024 int main(void) { const size_t N = SIZE; char str[N]; const char *example = "Hello World"; snprintf(str, sizeof(str), "%s", example); printf("Ssortingng = %s, Length = %zu\n", str, strlen(str)); return 0; } 

Qui imprime:

 Ssortingng = Hello World, Length = 11 

Cet exemple montre que snprintf() copié sur "Hello World" dans str , et a également ajouté un terminateur \0 à la fin.

Remarque: strlen() ne fonctionne que sur les chaînes terminées par un caractère null et provoque un comportement indéfini si la chaîne n’est pas terminée par un caractère null. snprintf() également besoin de davantage de vérifications d’erreur, qui peuvent être trouvées sur la page de manuel .

Comme d’autres l’ont dit, ce n’est pas une approche efficace, mais c’est là si vous cherchez.

Comme alternative à la réponse suggérée par snprintf() : (Remarque: problème si n <= 0 )

 size_t sz = sizeof buf; /*n is the number of characters to be copied from source*/ int n = (int) sz - 1; snprintf(buf, sz, "%s", src); 

Le code peut utiliser la précision suivante:

"... le nombre maximal d'octets à écrire pour s conversions. ..." C11 §7.21.6.1 4

 sprintf(buf, "%.*s", n, src); 

Il a l'avantage subtil en ce que src ne doit pas nécessairement être une chaîne , mais un tableau de caractères.

Un autre outil pour les chaînes.

Utilisez la fonction strlcpy() . strlcpy() prend toute la taille du tampon de destination et garantit une terminaison NULL s’il y a de la place. Lisez la page de manuel pour plus d’informations.

Si le comportement souhaité est une version strcpy de strcpy qui copie le préfixe initial le plus long de la chaîne source dans un tampon de taille connue, plusieurs options s’offrent à vous:

  • Vous pouvez écrire une fonction sur mesure qui fait le travail:

     char *safe_strcpy(char *dest, size_t size, char *src) { if (size > 0) { size_t i; for (i = 0; i < size - 1 && src[i]; i++) { dest[i] = src[i]; } dest[i] = '\0'; } return dest; } 

    La plupart des systèmes BSD ont une fonction strlcpy(char *dest, const char *src, size_t n); qui fonctionne de la même manière. L'ordre de ses arguments est déroutant car n est la taille du tableau dest , mais vient après l'argument src .

  • Vous pouvez utiliser strncat() :

     char *safe_strcpy(char *dest, size_t size, char *src) { if (size > 0) { *dest = '\0'; strncat(dest, src, n - 1); } return dest; } 
  • Vous pouvez utiliser snprintf() ou sprintf() , mais vous avez l'impression d'utiliser une presse hydraulique pour percer un clou:

     snprintf(dest, size, "%s", src); 

    Alternativement:

     if (size > 0) { sprintf(dest, "%.*s", (int)(size - 1), src); } 
  • Vous pouvez utiliser strlen() et memcpy() , mais cela n’est possible que si vous savez que le ptr source pointe vers une chaîne terminée par un caractère null. Il est également moins efficace que les deux solutions ci-dessus si la chaîne source est beaucoup plus longue que le tableau de destination:

     char *safe_strcpy(char *dest, size_t size, char *src) { if (size > 0) { size_t len = strlen(src); if (len >= size) len = size - 1; memcpy(dest, src, len); dest[len] = '\0'; } return dest; } 
  • Vous pouvez utiliser strncpy() et forcer la terminaison nulle. Cela serait inefficace si le tableau de destination est volumineux, car strncpy() remplit également le rest du tableau de destination. Il sera nul en octets si la chaîne source est plus courte. la sémantique de cette fonction est très contre-intuitive, mal comprise et sujette aux erreurs. Même strncpy() sont utilisés correctement, strncpy() est un bogue en attente, car le prochain programmeur, plus audacieux mais moins averti, pourrait modifier le code et l'introduire dans une tentative d'optimisation du code qu'il ne comprend pas. Jouez la sécurité: évitez cette fonction.

Pour illustrer le fait qu’il faut utiliser une alternative à strncpy() , considérons Git 2.19 (Q3 2018), qui constate qu’il est trop facile d’abuser des fonctions de l’API système telles que strcat (); strncpy() ; … ces fonctions sélectionnées sont maintenant interdites dans cette base de code et provoqueront un échec de la compilation.

Ce patch énumère plusieurs alternatives, ce qui le rend pertinent pour cette question.

Voir commit e488b7a , commit cc8fdae , commit 1b11b64 (24 juil. 2018) et commit c8af66a (26 juil. 2018) de Jeff King ( peff ) .
(Fusion de Junio ​​C Hamano – gitster – in commit e28daf2 , 15 août 2018)

banned.h : marque strncpy() comme interdit

La fonction strncpy() est moins horrible que strcpy() , mais rest assez facile à utiliser à cause de sa sémantique de terminaison amusante.
À savoir que s’il est tronqué, il omet le terminateur NUL et vous devez vous rappeler de l’append vous-même. Même si vous l’utilisez correctement, il est parfois difficile pour un lecteur de vérifier cela sans parcourir le code.
Si vous envisagez de l’utiliser, considérez plutôt:

  • strlcpy() si vous avez vraiment besoin d’une chaîne tronquée mais terminée par NUL (nous fournissons une version compat pour qu’elle soit toujours disponible)
  • xsnprintf() si vous êtes sûr que ce que vous copiez devrait correspondre
  • strbuf ou xstrfmt() si vous devez gérer des chaînes de longueur arbitraire allouées.

Notez qu’il existe une instance de strncpy dans compat/regex/regcomp.c , ce qui est compat/regex/regcomp.c (elle alloue une chaîne suffisamment grande avant la copie).
Mais cela ne déclenche pas la liste de ban même lors de la compilation avec NO_REGEX=1 , car:

  1. nous n’utilisons pas git-compat-util.h pour le comstackr (au lieu de cela, nous nous appuyons sur le système inclus dans la bibliothèque en amont); et
  2. C’est dans un #ifdef DEBUG#ifdef DEBUG

Comme il ne déclenche pas le code banned.h , il est préférable de le laisser pour garder notre divergence minimale en amont.

La fonction strcpy toujours par null. Bien sûr, vous devriez inclure du code pour éviter les débordements de tampon, par exemple:

 char buf[50]; if (strlen(src) >= sizeof buf) { // do something else... } else strcpy(buf, src);