OVH Cloud OVH Cloud

Proposition man strcpy, strncpy

22 réponses
Avatar
Marc Boyer
Bonjour,

suite à de précedentes discussions, je vais faire une nouvelle
proposition pour les pages de man Linux de strcpy, strncpy,
strcat, strncat.

Voici ma proposition actuelle pour strcpy, strncpy. Tous
commentaires bienvenus.


STRCPY(3) Linux Programmer's Manual STRCPY(3)

NAME
strcpy, strncpy - copy a string

SYNOPSIS
#include <string.h>

char *strcpy(char *dest, const char *src);

char *strncpy(char *dest, const char *src, size_t n);

DESCRIPTION
The strcpy() function copies the string pointed to by src (including
the terminating `\0' character) to the array pointed to by dest. The
strings may not overlap, and the destination string dest must be large
enough to receive the copy.

The strncpy() function is similar, except that not more than n bytes of
src are copied. Thus, if there is no null byte among the first n bytes
of src, the result will not be null-terminated.

In the case where the length of src is less than that of n, the remain-
der of dest will be padded with nulls.

An (very poor quality) implementation of strncpy() could be

char*
strncpy(char *dest, const char *src, size_t n){
size_t i;
for(i=0 ; i < strlen(src) && i < n; i++){
dest[i]= src[i];
}
for(i=strlen(src)+1 ; i < n ; i++){
dest[i]= '\O';
}
return dest;
}

RETURN VALUE
The strcpy() and strncpy() functions return a pointer to the destina-
tion string dest.

BUGS
If the destination string of a strcpy() is not large enough (that is,
if the programmer was stupid/lazy, and failed to check the size before
copying) then anything might happen. Overflowing fixed length strings
is a favourite cracker technique.

A common mistake with strncpy() is to forget that it, if
strlen(src) >= n, then, the '\O' termination character is not set.

NOTE
Some programmers consider strncpy() as useless. If the programmer knows
the the size of dest is greater than the length of src, then, strcpy()
can be used. Otherwise, using strncpy() makes a non null terminated
string.

At least, lazy programmers should write:
strncpy(foo, bar, n);
foo[n-1]= '\0';

CONFORMING TO
SVID 3, POSIX, BSD 4.3, ISO 9899

SEE ALSO
bcopy(3), memccpy(3), memcpy(3), memmove(3)

GNU 1993-04-11 STRCPY(3)

--
La contractualisation de la recherche, c'est me donner de l'argent pour
faire ce que je ne sais pas faire, que je fais donc mal, pendant que ce
que je sais faire, je le fais sans moyens...

10 réponses

1 2 3
Avatar
Charlie Gordon
"Marc Boyer" wrote in message
news:cl5ed6$7p4$
Bonjour,

suite à de précedentes discussions, je vais faire une nouvelle
proposition pour les pages de man Linux de strcpy, strncpy,
strcat, strncat.

Voici ma proposition actuelle pour strcpy, strncpy. Tous
commentaires bienvenus.


Salut, et merci à toi de cet effort.


STRCPY(3) Linux Programmer's Manual STRCPY(3)

NAME
strcpy, strncpy - copy a string

SYNOPSIS
#include <string.h>

char *strcpy(char *dest, const char *src);

char *strncpy(char *dest, const char *src, size_t n);

DESCRIPTION
The strcpy() function copies the string pointed to by src (including
the terminating `' character) to the array pointed to by dest. The
strings may not overlap, and the destination string dest must be large
enough to receive the copy.

The strncpy() function is similar, except that not more than n bytes of
src are copied. Thus, if there is no null byte among the first n bytes
of src, the result will not be null-terminated.

In the case where the length of src is less than that of n, the remain-
der of dest will be padded with nulls.


Je dirais: the length of src is less than n

An (very poor quality) implementation of strncpy() could be

char*
strncpy(char *dest, const char *src, size_t n){
size_t i;
for(i=0 ; i < strlen(src) && i < n; i++){
dest[i]= src[i];
}
for(i=strlen(src)+1 ; i < n ; i++){
dest[i]= 'O';
}
return dest;
}

Very poor quality indeed ;-)

Je pense qu'il faut une illustration plus pertinente : certes le code d'une page
de manuel doit etre abordable par le programmeur débutant, mais c'est vraiment
dommage d'y mettre des horreurs comme i < strlen(src) dans le test de la boucle
;-).
De plus, le test sur i<n doit etre fait avant de déréférencer src pour le cas ou
n==0
Enfin l'initialisation de i dans la deuxieme boucle est fausse et d'ailleurs
inutile.
Je propose cette version :

strncpy could be implemented as:

char *strncpy(char *dest, const char *src, size_t n) {
size_t i;
for (i = 0; i < n && src[i] != ''; i++)
dest[i]= src[i];
for (; i < n; i++)
dest[i] = '';
return dest;
}

RETURN VALUE
The strcpy() and strncpy() functions return a pointer to the destina-
tion string dest.

BUGS
If the destination string of a strcpy() is not large enough (that is,
if the programmer was stupid/lazy, and failed to check the size before
copying) then anything might happen. Overflowing fixed length strings
is a favourite cracker technique.

A common mistake with strncpy() is to forget that it, if
strlen(src) >= n, then, the 'O' termination character is not set.

NOTE
Some programmers consider strncpy() as useless. If the programmer knows
the the size of dest is greater than the length of src, then, strcpy()
can be used. Otherwise, using strncpy() makes a non null terminated
string.


Comme je me sens visé par la NOTE, je tiens à préciser ma position qui est
légèrement différente de ce que tu écris :

Some programmers consider strncpy() inefficient and error prone. They recommend
against using it.


At least, lazy programmers should write:
strncpy(foo, bar, n);
foo[n-1]= '';


J'éviterais les termes désobligeants comme 'stupid' et 'lazy'.
L'exemple final qui correspond à un usage très répandu mais sémantiquement
bancal de strncpy, devrait être présenté de façon plus prudente :

Programmers often prevent this mistake by forcing '' termination this way:

strncpy(buf, str, n);
buf[n - 1] = '';

But even this simple idiom is not failsafe as it is incorrect for n equal to 0.

CONFORMING TO
SVID 3, POSIX, BSD 4.3, ISO 9899

SEE ALSO
bcopy(3), memccpy(3), memcpy(3), memmove(3)

GNU 1993-04-11 STRCPY(3)

--
La contractualisation de la recherche, c'est me donner de l'argent pour
faire ce que je ne sais pas faire, que je fais donc mal, pendant que ce
que je sais faire, je le fais sans moyens...


Chqrlie.

Avatar
DINH Viêt Hoà

char *strncpy(char *dest, const char *src, size_t n) {
size_t i;
for (i = 0; i < n && src[i] != ''; i++)
dest[i]= src[i];
for (; i < n; i++)


ah ben bravo ! une boucle for sans initialization !
à la rigueur, dans ce cas, je préfère poser une variable intermédiaire.

J'éviterais les termes désobligeants comme 'stupid' et 'lazy'.


Ah non, 'lazy' plutôt gratifiant. L'informatique est fait pour les
gens paresseux. Quand à 'stupid', c'est un peu la situation dans
laquelle tu te retrouves quand tu codes bourré.

--
DINH V. Hoa,

"Parait-il que c'est ce que rechechent la majorité des djeunz. Il n'y a plus
aucun attrait pour les métiers scientifiques ni techniques. Ils veulent être
chanteur, acteur ou fonctionnaire. C'est désépérant..." -- Emmanuel Delahaye

Avatar
Charlie Gordon
"DINH Viêt Hoà" wrote in message
news:

char *strncpy(char *dest, const char *src, size_t n) {
size_t i;
for (i = 0; i < n && src[i] != ''; i++)
dest[i]= src[i];
for (; i < n; i++)


ah ben bravo ! une boucle for sans initialization !
à la rigueur, dans ce cas, je préfère poser une variable intermédiaire.


Cette boucle ne correspond pas à l'usage habituel, donc tu proposerais un
deuxieme indice et :

for (j = i; j < n; j++)
p[j] = ''

je préfère encore remplacer la deuxieme boucle for() par un while() :

while (i < n)
p[i++] = '';

ou encore :

memset(p + i, 0, n - i);

ce qui aurait l'avantage d'insister lourdement sur l'inefficacité de cette
fonction stupide pour un effet de bord dont l'intérêt est rarissime.


J'éviterais les termes désobligeants comme 'stupid' et 'lazy'.


Ah non, 'lazy' plutôt gratifiant. L'informatique est fait pour les
gens paresseux. Quand à 'stupid', c'est un peu la situation dans
laquelle tu te retrouves quand tu codes bourré.


Oui nous sommes d'accord : lazy n'est pas nécessairement un défaut, et il n'est
pas utilisé à bon escient dans le texte de Marc. Qui plus est c'est quand même
un terme péjoratif pour beaucoup de lecteurs. Les pages de manuel doivent
identifier les problèmes potentiels, mais pas insulter les programmeurs ;-)

Chqrlie.

PS: Les coquilles dans la citation sont-elles intentionnelles ?

"Parait-il que c'est ce que rechechent la majorité des djeunz. Il n'y a plus
aucun attrait pour les métiers scientifiques ni techniques. Ils veulent être
chanteur, acteur ou fonctionnaire. C'est désépérant..." -- Emmanuel Delahaye


Avatar
DINH Viêt Hoà

memset(p + i, 0, n - i);


pas classe.

PS: Les coquilles dans la citation sont-elles intentionnelles ?


non, je corrige de ce pas.

--
DINH V. Hoa,

"toujours donner une bonne image de ses idoles" -- Billy

Avatar
Charlie Gordon
"DINH Viêt Hoà" wrote in message
news:

memset(p + i, 0, n - i);


pas classe.


Qu'est-ce qui te gêne ? De toute façon, il n'y a pas de classes en C ;-)

Chqrlie.


Avatar
DINH Viêt Hoà

"DINH Viêt Hoà" wrote in message
news:

memset(p + i, 0, n - i);


pas classe.


Qu'est-ce qui te gêne ? De toute façon, il n'y a pas de classes en C ;-)


juste qu'algorithmiquement, memset() n'est pas forcément très explicite.

--
DINH V. Hoa,

"la chatte de ma petite soeur s'appelle Zoé" -- the captain de soirées



Avatar
Charlie Gordon
"DINH Viêt Hoà" wrote in message
news:

"DINH Viêt Hoà" wrote in message
news:

memset(p + i, 0, n - i);


pas classe.


Qu'est-ce qui te gêne ? De toute façon, il n'y a pas de classes en C ;-)


juste qu'algorithmiquement, memset() n'est pas forcément très explicite.


Ce n'était pas ma premiere solution non plus.
Mais je trouve memset très explicite !

Chqrlie




Avatar
Marc Boyer
Yves ROMAN wrote:
Yves ROMAN wrote:
dest[strlen(src)] ?
Je comprends pas ta remarque.



la première boucle se termine en mettant à jour dest[strlen(src)-1]
et la suivante commence par dest[strlen(src)+1].

Le '' final de src n'est donc jamais copié vers dest
Il faudrait soit le copier dans la 1ère boucle,
for(i=0 ; i <= strlen(src) && i < n; i++){
soit le forcer dans la 2ème
for(i=strlen(src) ; i < n ; i++){


OK, merci de la remarque.

Marc Boyer
--
La contractualisation de la recherche, c'est me donner de l'argent pour
faire ce que je ne sais pas faire, que je fais donc mal, pendant que ce
que je sais faire, je le fais sans moyens...


Avatar
Marc Boyer
In article <cl6o5o$hr7$, Charlie Gordon wrote:
"Marc Boyer" wrote in message
news:cl5ed6$7p4$
In the case where the length of src is less than that of n, the remain-
der of dest will be padded with nulls.


Je dirais: the length of src is less than n


Voui, erreur de copier/coller.

An (very poor quality) implementation of strncpy() could be

char*
strncpy(char *dest, const char *src, size_t n){
size_t i;
for(i=0 ; i < strlen(src) && i < n; i++){
dest[i]= src[i];
}
for(i=strlen(src)+1 ; i < n ; i++){
dest[i]= 'O';
}
return dest;
}

Very poor quality indeed ;-)

Je pense qu'il faut une illustration plus pertinente : certes le code d'une page
de manuel doit etre abordable par le programmeur débutant, mais c'est vraiment
dommage d'y mettre des horreurs comme i < strlen(src) dans le test de la boucle
;-).


D'autant plus que dans strncat, j'ai pris la peine de passer par une var
intermédiaire. Essayons d'être cohérent.

De plus, le test sur i<n doit etre fait avant de déréférencer src pour le cas ou
n==0


Alors là, ça devient rude à écrire.

strncpy could be implemented as:

char *strncpy(char *dest, const char *src, size_t n) {
size_t i;
for (i = 0; i < n && src[i] != ''; i++)
dest[i]= src[i];
for (; i < n; i++)
dest[i] = '';
return dest;
}


Non, si je veux toucher aussi les débutants, je préfère strlen,
mais en effet, si n==0, faut pas appeller strlen().
Je préfère une garde globale.

Par contre, je vais garder le for sans initialiseur: je pense
que ça peut suprendre un débutant, mais pas l'empécher de comprendre
le code.

char*
strncpy(char *restrict dest, const char *restrict src, size_t n){
if (n != 0) {
size_t src_len= strlen(src);
size_t i;
for(i=0 ; i < src_len && i < n; i++)
dest[i]= src[i];
for( ; i < n ; i++)
dest[i]= '';
}

return dest;
}


NOTE
Some programmers consider strncpy() as useless. If the programmer knows
the the size of dest is greater than the length of src, then, strcpy()
can be used. Otherwise, using strncpy() makes a non null terminated
string.


Comme je me sens visé par la NOTE,


Oui ;-)
Mais je m'inclus aussi dedans. Disons que tu m'a fait mettre le doigt
sur quelque chose.

je tiens à préciser ma position qui est légèrement différente de ce que tu écris :

Some programmers consider strncpy() inefficient and error prone. They recommend
against using it.


At least, lazy programmers should write:
strncpy(foo, bar, n);
foo[n-1]= '';


J'éviterais les termes désobligeants comme 'stupid' et 'lazy'.


'stupid' et 'lazy' étaient dans la version initiale de la page.
Je n'ai gardé que 'lazy' sur ce que j'ai ajouté.

L'exemple final qui correspond à un usage très répandu


Je savais pas.

mais sémantiquement
bancal de strncpy, devrait être présenté de façon plus prudente :

Programmers often prevent this mistake by forcing '' termination this way:

strncpy(buf, str, n);
buf[n - 1] = '';

But even this simple idiom is not failsafe as it is incorrect for n equal to 0.


Et que penses-tu de:

Programmers often prevent this mistake by forcing '' termination
this way:

strncpy(buf, str, n);
if (n) buf[n - 1]= '';

If n can not be nul, the test can be removed.

Marc Boyer
--
La contractualisation de la recherche, c'est me donner de l'argent pour
faire ce que je ne sais pas faire, que je fais donc mal, pendant que ce
que je sais faire, je le fais sans moyens...


Avatar
Charlie Gordon
"Marc Boyer" wrote in message
news:clah72$e3p$
In article <cl6o5o$hr7$, Charlie Gordon wrote:
"Marc Boyer" wrote in message
news:cl5ed6$7p4$

char*
strncpy(char *dest, const char *src, size_t n){
size_t i;
for(i=0 ; i < strlen(src) && i < n; i++){
dest[i]= src[i];
}
for(i=strlen(src)+1 ; i < n ; i++){
dest[i]= 'O';
}
return dest;
}

Very poor quality indeed ;-)

Je pense qu'il faut une illustration plus pertinente : certes le code d'une
page


de manuel doit etre abordable par le programmeur débutant, mais c'est
vraiment


dommage d'y mettre des horreurs comme i < strlen(src) dans le test de la
boucle


;-).


D'autant plus que dans strncat, j'ai pris la peine de passer par une var
intermédiaire. Essayons d'être cohérent.

De plus, le test sur i<n doit etre fait avant de déréférencer src pour le
cas ou


n==0


Alors là, ça devient rude à écrire.


En fait c'est très simple : dans ton exemple, il suffit d'écrire : i < n && i <
strlen(src)
Le problème avec strlen(src) c'est que c'est un très mauvais exemple pour les
lecteur de la page de manuel à cause de l'inefficacité crasse que cela implique
pour un test de boucle. De plus c'est sémantiquement incorrect pour strncpy ou
src peut très bien ne pas contenir de '' final et strlen(src) a donc
potentiellement un comportement indéfini.

strncpy could be implemented as:

char *strncpy(char *dest, const char *src, size_t n) {
size_t i;
for (i = 0; i < n && src[i] != ''; i++)
dest[i]= src[i];
for (; i < n; i++)
dest[i] = '';
return dest;
}


Non, si je veux toucher aussi les débutants, je préfère strlen,
mais en effet, si n==0, faut pas appeller strlen().


pas seulement dans ce cas (cf plus haut). strlen n'est pas une option, il faut
en passer par le test de ''.
ou utiliser strnlen() comme c'est le cas dans la glibc. Mais cette fonction
n'est pas standard :-(

J'éviterais les termes désobligeants comme 'stupid' et 'lazy'.


'stupid' et 'lazy' étaient dans la version initiale de la page.
Je n'ai gardé que 'lazy' sur ce que j'ai ajouté.


Effectivement, les pages ne sont pas un modèle de convivialité ;-)

Et que penses-tu de:

Programmers often prevent this mistake by forcing '' termination
this way:

strncpy(buf, str, n);
if (n) buf[n - 1]= '';

If n can not be nul, the test can be removed.


Je dirais alors:

if (n != 0) {
strncpy(buf, str, n);
buf[n - 1] = '';
}

ce qui a le même résultat, mais met l'emphase sur le comportement vide dans le
cas n==0, qui n'est pas si évident dans ton code.

Chqrlie.



1 2 3