strncpy, strncpy_s
| Défini dans l'en-tête <string.h>
|
||
char* strncpy( char* dest, const char* src, size_t count );
|
(1) | (jusqu'à C99) |
char* strncpy( char* restrict dest, const char* restrict src, size_t count );
|
(depuis C99) | |
errno_t strncpy_s( char* restrict dest, rsize_t destsz,
const char* restrict src, rsize_t count );
|
(2) | (depuis C11) |
count caractères du tableau de caractères pointé par src (y compris le caractère nul de terminaison, mais pas les caractères qui le suivent) vers le tableau de caractères pointé par dest.count est atteint avant que tout le tableau src ait été copié, le tableau de caractères résultant n'est pas terminé par un caractère nul.src, count n'est pas atteint, des caractères nuls supplémentaires sont écrits dans dest jusqu'à ce qu'un total de count caractères aient été écrits.dest ou src n'est pas un pointeur vers un tableau de caractères (y compris si dest ou src est un pointeur nul), si la taille du tableau pointé par dest est inférieure à count, ou si la taille du tableau pointé par src est inférieure à count et qu'il ne contient pas de caractère nul.count, elle s'arrête après avoir écrit le caractère nul de terminaison (s'il n'y avait pas de nul dans la source, elle en écrit un à dest[count] puis s'arrête). De plus, les erreurs suivantes sont détectées à l'exécution et appellent la fonction gestionnaire de contrainte actuellement installée :
srcoudestest un pointeur nuldestszest nul ou supérieur à RSIZE_MAXcountest supérieur à RSIZE_MAXcountest supérieur ou égal àdestsz, maisdestszest inférieur ou égal àstrnlen_s(src, count), en d'autres termes, une troncature se produirait- Un chevauchement se produirait entre les chaînes source et destination
dest < strnlen_s(src, destsz) <= destsz; en d'autres termes, une valeur erronée de destsz n'expose pas le débordement de tampon imminent. Le comportement est indéfini si la taille du tableau de caractères pointé par src < strnlen_s(src, count) < destsz; en d'autres termes, une valeur erronée de count n'expose pas le débordement de tampon imminent.strncpy_s n'est garanti d'être disponible que si __STDC_LIB_EXT1__ est défini par l'implémentation et si l'utilisateur définit __STDC_WANT_LIB_EXT1__ comme la constante entière 1 avant d'inclure <string.h>.Paramètres
| dest | - | pointeur vers le tableau de caractères à copier |
| src | - | pointeur vers le tableau de caractères à copier |
| count | - | nombre maximal de caractères à copier |
| destsz | - | la taille du tampon de destination |
Valeur de retour
destdest[0] (sauf si dest est un pointeur nul ou destsz est nul ou supérieur à RSIZE_MAX) et peut altérer le reste du tableau de destination avec des valeurs non spécifiées.Notes
Corrigé par le DR 468 post-C11, strncpy_s, contrairement à strcpy, n'est autorisé à altérer le reste du tableau de destination qu'en cas d'erreur.
Contrairement à strncpy, strncpy_s ne remplit pas le tableau de destination avec des zéros, ce qui est une source fréquente d'erreurs lors de la conversion de code existant vers la version avec vérification des limites.
Bien que la troncature pour s'adapter au tampon de destination soit un risque de sécurité et donc une violation de contrainte d'exécution pour strncpy_s, il est possible d'obtenir un comportement de troncature en spécifiant count égal à la taille du tableau de destination moins un : il copiera les premiers count octets et ajoutera le terminateur nul comme toujours : strncpy_s(dst, sizeof dst, src, (sizeof dst)-1);
Exemple
#define __STDC_WANT_LIB_EXT1__ 1
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char src[] = "hi";
char dest[6] = "abcdef"; // no null terminator
strncpy(dest, src, 5); // writes five characters 'h', 'i', '\0', '\0', '\0' to dest
printf("strncpy(dest, src, 5) to a 6-byte dest gives : ");
for (size_t n = 0; n < sizeof dest; ++n) {
char c = dest[n];
c ? printf("'%c' ", c) : printf("'\\0' ");
}
printf("\nstrncpy(dest2, src, 2) to a 2-byte dst gives : ");
char dest2[2];
strncpy(dest2, src, 2); // truncation: writes two characters 'h', 'i', to dest2
for (size_t n = 0; n < sizeof dest2; ++n) {
char c = dest2[n];
c ? printf("'%c' ", c) : printf("'\\0' ");
}
printf("\n");
#ifdef __STDC_LIB_EXT1__
set_constraint_handler_s(ignore_handler_s);
char dst1[6], src1[100] = "hello";
errno_t r1 = strncpy_s(dst1, 6, src1, 100); // writes 0 to r1, 6 characters to dst1
printf("dst1 = \"%s\", r1 = %d\n", dst1,r1); // 'h','e','l','l','o','\0' to dst1
char dst2[5], src2[7] = {'g','o','o','d','b','y','e'};
errno_t r2 = strncpy_s(dst2, 5, src2, 7); // copy overflows the destination array
printf("dst2 = \"%s\", r2 = %d\n", dst2,r2); // writes nonzero to r2,'\0' to dst2[0]
char dst3[5];
errno_t r3 = strncpy_s(dst3, 5, src2, 4); // writes 0 to r3, 5 characters to dst3
printf("dst3 = \"%s\", r3 = %d\n", dst3,r3); // 'g', 'o', 'o', 'd', '\0' to dst3
#endif
}
Résultat possible :
strncpy(dest, src, 5) to a 6-byte dst gives : 'h' 'i' '\0' '\0' '\0' 'f'
strncpy(dest2, src, 2) to a 2-byte dst gives : 'h' 'i'
dst1 = "hello", r1 = 0
dst2 = "", r2 = 22
dst3 = "good", r3 = 0
Références
- Norme C23 (ISO/IEC 9899:2024) :
- 7.24.2.4 La fonction strncpy (p : TBD)
- K.3.7.1.4 La fonction strncpy_s (p : TBD)
- Norme C17 (ISO/IEC 9899:2018) :
- 7.24.2.4 La fonction strncpy (p : 265)
- K.3.7.1.4 La fonction strncpy_s (p : 447-448)
- Norme C11 (ISO/IEC 9899:2011) :
- 7.24.2.4 La fonction strncpy (p : 363-364)
- K.3.7.1.4 La fonction strncpy_s (p : 616-617)
- Norme C99 (ISO/IEC 9899:1999) :
- 7.21.2.4 La fonction strncpy (p : 326-327)
- Norme C89/C90 (ISO/IEC 9899:1990) :
- 4.11.2.4 La fonction strncpy
Voir aussi
(C11) |
copie une chaîne vers une autre (fonction) |
(C11) |
copie un tampon vers un autre (fonction) |
(dynamic memory TR) |
alloue une copie d'une chaîne jusqu'à une taille spécifiée (fonction) |
Documentation C++ pour strncpy
| |