7
votes

Si la destination et la source sont les mêmes, que font Memmove?

Si la destination et la source sont les mêmes, le Memmove toujours "déplace" les données (ou renvoie-t-il directement)? Qu'en est-il de realloc ; Et si la nouvelle taille est la même que l'ancienne taille?


4 Réponses :


4
votes

Cela va vraiment être spécifique à la mise en œuvre. Ce serait une bonne pratique de le faire, bien sûr, mais cela dépend vraiment quel la mise en œuvre que vous voulez dire.

Cela va travailler de toute façon, mais probablement une implémentation convenablement intelligente vérifierait des segments qui se chevauchent (et en particulier pour le cas où source == devoir ) et le gérer correctement.


2 commentaires

En fait, je suis en désaccord que ce serait une bonne pratique. Supposons que vous déménageez de minuscules blocs de mémoire, un test et une branche potentielle de réprédication pourraient être un prix très coûteux pour l'hypothèse que le programmeur ne sait pas ce qu'il fait. Cela dit, si les arguments peuvent être déterminés au moment de la compilation pour être égaux, il serait bon de le faire (E.g: Utilisation de GCC __ Basculin_CONSTANT_P )


@ninjalj, bon point. Le point réel que je faisais était qu'il n'ya aucune garantie de ce comportement et une mise en œuvre est essentiellement de faire tout ce qu'elle veut (dans la raison ...)



1
votes

Autant que je sache, aucune norme ne donne aucune promesse sur le retour immédiatement dans ce cas, vous ne devriez donc pas vous attendre à ce comportement.

Mieux vaut ne pas passer des pointeurs non valides dans l'espoir que cela ne va pas accéder aux données; -)


2 commentaires

"Pointeurs non valides". Il n'y a rien de mal à avoir une source et une destination identiques. En supposant, bien sûr, que des données valides peuvent être lues là-bas. Je suppose que votre point est que nous ne devrions pas nous attendre à Memmove (NULL, NULL, 1) fonctionner?


Plus ou moins. Ce que je veux dire, c'est oui, nous ne devrions pas passer des pointeurs non valides (null ou autre zone inaccessible ou réadonnée) dans l'espoir que Memmove ne fera rien puisqu'il est pareil.



0
votes

au moins pour realloc , il est implicitement supposé qu'une condition "non nécessaire nécessaire" existe et est valide, car le déplacement est noté comme cas spécial:

La fonction REALLOC () doit modifier la taille de l'objet de mémoire pointée par PTR à la taille spécifiée par la taille. Le contenu de l'objet reste inchangé jusqu'au moindre des nouvelles tailles. si la nouvelle taille de l'objet mémoire nécessiterait un mouvement de l'objet, l'espace de l'instanciation précédente de l'objet est libéré.

Le libellé "si ... [...] suggère que ce n'est pas nécessairement toujours aussi. Bien sûr, il y a aucune exigence pour une implémentation pour omettre une copie qui n'est pas nécessaire.

La seule condition requise pour MemMove est que l'effet final est identique à celui que si les données ont été copiées sur un tampon temporaire d'abord puis copié à la destination finale. Cette contrainte "comme si" permet de copier des régions qui se chevauchent sans données de corruption (aucune implémentation que je connais vraiment copies à un tampon temporaire d'abord).

Donc, en un mot: non spécifié.



0
votes

Comme d'autres l'ont dit, la spécification ne nécessite pas de raccourci et que ce n'est pas clair lorsque l'ajout de la branche supplémentaire améliore réellement les performances.

Mais cela ne répond pas à la question de ce qui se passe réellement lorsque vous appelez MemMove code>. J'ai creusé le code source Glibc et j'ai trouvé de nombreuses implémentations d'assemblage pour diverses architectures avec une implémentation C portable C. P>

Le TL; DR est que la version PURE C n'est pas raccourci, mais la version de l'assemblage X86_64 ( Je pense). P>

La version PURE C est une boucle MEMMOVE assez standard. L'astuce est que si vous déplacez 16 kib ou plus, il manipulera la mémoire virtuelle au lieu de copier des octets. La fonction est définie dans String / Memmove. C , et la viande de la mise en œuvre est le byte_copy_fwd code> macro de sysdeps / générique / memcopy.h . p>

pour l'assemblage X86_64, il existe plusieurs versions en fonction des instructions disponibles (par exemple AVX, SSE, etc.). Celles-ci sont dans SYSDEPS / X86_64 / MULIATCH .


est une implémentation de Memmove-Vec-non aligné-erms.s qui utilise un représentant amélioré MOVSB ​​(ERMS): P>
ENTRY (__memmove_erms)
        movq    %rdi, %rax
        /* Skip zero length.  */
        test    %RDX_LP, %RDX_LP
        jz      2f
L(start_movsb):
        mov     %RDX_LP, %RCX_LP
        cmp     %RSI_LP, %RDI_LP
        jb      1f
        /* Source == destination is less common.  */
        je      2f
        lea     (%rsi,%rcx), %RDX_LP
        cmp     %RDX_LP, %RDI_LP
        jb      L(movsb_backward)
1:
        rep movsb
2:
        ret
L(movsb_backward):
        leaq    -1(%rdi,%rcx), %rdi
        leaq    -1(%rsi,%rcx), %rsi
        std
        rep movsb
        cld
        ret
END (__memmove_erms)


0 commentaires