C'est un exercice d'apprentissage. J'essaie d'augmenter MemCy en notifiant l'utilisateur si l'opération de copie passera ou échoue avant de commencer. Ma plus grande question est la suivante. Si j'alloque deux tableaux de caractère de 100 octets chacun et que deux pointeurs font référence à chaque tableau, comment savoir quelle direction je copie? Si je copie tout de la première matrice à la seconde comment puis-je vous assurer que l'utilisateur n'écrase pas le tableau d'origine?
Ma solution actuelle compare la distance des pointeurs de la taille de la matrice de destination. Si la taille entre est inférieure à celle que je dis qu'un écrasement se produira. Mais que si sa copie dans l'autre direction? Je suis juste une sorte de confusion. P>
3 Réponses :
Ce que vous voulez vérifier est la position en mémoire de la source relativement à la destination:
Si la source est en avance sur la destination (c.-à-d. Source Voici quelques dessins d'ASCII brute pour visualiser le problème. P> |_;_;_;_;_;_| (source)
|_;_;_;_;_;_| (destination)
>-----^ start from the end to shift the values to the right
|_;_;_;_;_;_| (source)
|_;_;_;_;_;_| (destination)
^-----< start from the beginning to shift the values to the left
Une situation supplémentaire est source code> et
de destination code> pointant sur différents objets, auquel cas
source
(uintptr_t) <(uintptr_T) code>.
En effet, les pointeurs sont nuls *. Au lieu de comparer, nous pourrions calculer la différence à l'origine de l'OP.
Dans l'exemple original, les tableaux src code> et
dst code> sont deux objets distincts. Ils ne peuvent pas se chevaucher en raison d'être des objets distincts, mais cela signifie que
PTR1 - PTR2 code> dans l'exemple original est indéfini, comme cela serait le
ptr1
Ouais, la norme ne définit pas les soustractions de pointeur vide. GCC émet un simple avertissement en mode Pedantic.
Non seulement cela, mais "lorsque deux pointeurs sont soustraits, les deux doivent indiquer des éléments du même objet de tableau". Le comportement non défini est mauvais même lorsque votre compilateur n'a pas d'avertissement pour cela. Voir blog.regehr.org/archives/213 et blog.llvm.org/2011/05/... (version courte: Votre compilateur peut tirer parti des comportements non définis dans votre programme, des comportements non définis qu'il ne prévient pas, de faire des choses très étranges et inattendues. N'utilisez pas de comportement non défini)
Le seul portable portable em> pour déterminer si deux plages de mémoire se chevauchent sont les suivantes: int overlap_p(void *a, void *b, size_t n)
{
char *x = a, *y = b;
return (x<=y && x+n>y) || (y<=x && y+n>x);
}
@R - Si le deuxième code de code utilise x code> et
y code> plutôt que
a code> et
b code>?
Vous pouvez réduire l'arithmétique nominale en ajoutant char * z = b + n-1; code> et test
x + i == y || x + i == z code>, donc un deuxième addition pour
y + i code> dans chaque itération n'est pas nécessaire.
Je ne crois pas que "tente d'augmenter memcpy en notifiant l'utilisateur si l'opération de copie passera ou échoue avant de commencer." est une notion bien formée. P>
Premier, memcpy () ne réussit pas ou échoue au sens normal. Il suffit de copie les données, qui pourraient provoquer une erreur / exception si elle se lit en dehors de la matrice source ou écrit en dehors de la matrice de destination, et elle pourrait également lire ou écrire en dehors de l'un de ces tableaux sans causer de défaut / exception et juste de la corruption silencieuse. . Quand je dis "Memcpy fait cela", je ne parle pas de la mise en œuvre du memcpy C stdlib, mais à propos de toute fonction de la même signature - il n'a pas assez d'informations pour faire autrement. P>
Deuxièmement, si votre définition de "réussir" est "supposant que les tampons sont assez gros mais peuvent se chevaucher, copier les données de la source vers DST sans trébucher sur vous-même lors de la copie" - c'est bien ce que Memmove (), Et c'est toujours possible. Encore une fois, il n'y a pas de cas "défaillance de retour". Si les tampons ne se chevauchent pas, il est facile, si la source se chevauche la fin de la destination, vous ne copiez simplement que des octets d'octets depuis le début; Si la source se chevauche le début de la destination, vous ne copiez simplement pas d'octet par octet de la fin. Qui est ce que Memmove () fait. P>
Troisième, lors de la rédaction de ce type de code, vous devez faire très attention aux cas de débordement pour votre pointeur arithmétique (y compris l'addition, la soustraction et l'indexation de la matrice). Dans Val = ABS (PTR1 - PTR2) Code>,
PTR1 - PTR2 CODE> pourrait être un très grand nombre, et il sera non signé, donc
abs () code > Ne ferez rien, et
int code> est le mauvais type à stocker cela. Juste pour que vous sachiez. P>
"Je ne crois pas que" tenter d'augmenter memcpy en notifiant l'utilisateur si l'opération de copie passera ou échoue avant de commencer "est une notion bien formée" I> C'est ce que nous appelons Bikeshedding , et c'est probablement mieux à gauche en tant que commentaire. Les tampons chevauchants et l'utilisation de memcpy code> causent des problèmes dans la pratique. Voir, par exemple, lwn.net's's sur casser les choses et Changement de glibc Exposant les bogues ; et la discussion sur le flash d'Adobe.
MEMCY CODE> n'est pas garanti de fonctionner pour les régions qui se chevauchent, mais
MemMove code> est. Peut-être que vous souhaitez implémenter
MemMove code> sémantique?
C'est ce que signifie Memmove. Trouvez une source pour cela.
Où trouvez-vous le code source des fonctions C? Je vois leurs en-têtes dans / usr / incluent / ...
Essayez The Glibc ou ULIBC Code source.
memcpy () ne réussit pas ou échoue au sens normal. Il suffit de copie les données, qui pourraient provoquer une erreur / exception si elle se lit en dehors de la matrice source ou écrit en dehors de la matrice de destination, et elle pourrait également lire ou écrire en dehors de l'un de ces tableaux sans causer de défaut / exception et juste de la corruption silencieuse. . Quand je dis "Memcpy fait cela" Je ne parle pas de la mise en œuvre du memcpy C stdlib, mais à propos de toute fonction avec la même signature - il n'a pas assez d'informations à faire autrement.
Notez les personnes qui parlent de Memmove () au lieu de memcpy (): Si votre définition de "réussir" est "supposant que les tampons sont assez gros mais peuvent se chevaucher, copier les données de la source vers DST sans trébucher sur vous Je> tout en copiant "- c'est vraiment ce que Memmove () fait, mais c'est toujours possible. Si les tampons ne se chevauchent pas, il est facile, si la source se chevauche la fin de la destination, vous ne copiez simplement que des octets d'octets depuis le début; Si la source se chevauche le début de la destination, vous ne copiez simplement pas d'octet par octet de la fin. Qui est ce que Memmove () fait.