Je voulais voir si ressortingct
empêcherait memcpy
d’accéder à la mémoire qui se chevauchait.
La fonction memcpy
copie n octets de la zone mémoire src vers la zone mémoire destinée directement . Les zones de mémoire ne doivent pas se chevaucher.
memmove
utilise un tampon pour memmove
tout risque de chevauchement de mémoire.
Le qualificatif de ressortingct
indique que pendant la durée de vie du pointeur, seul le pointeur lui-même ou une valeur directement issue de celui-ci (tel que pointer + n
) aura access aux données de cet object. Si la déclaration d’intention n’est pas suivie et que l’object est accédé par un pointeur indépendant, cela entraînera un comportement indéfini.
#include #include #define SIZE 30 int main () { char *ressortingct itself; itself = malloc(SIZE); strcpy(itself, "Does ressortingct stop undefined behavior?"); printf("%d\n", &itself); memcpy(itself, itself, SIZE); puts(itself); printf("%d\n", &itself); memcpy(itself-14, itself, SIZE); //intentionally trying to access ressortingcted memory puts(itself); printf("%d\n", &itself); return (0); }
Sortie ()
Adresse de lui-même: 12345
Est-ce que restreindre arrête un comportement non défini?
Adresse de lui-même: 12345
arrêter un comportement indéfini bop indéfini?
Adresse de lui-même: 12345
Est- memcpy
que memcpy
utilise un pointeur indépendant? Parce que la sortie montre clairement un comportement indéfini et que ressortingct
n’empêche pas l’access à la mémoire qui se chevauche avec memcpy
.
Je suppose que memcpy
a un avantage en memcpy
performances puisqu’il copie directement les données, tandis que memmove
utilise un tampon. Mais avec les ordinateurs modernes, devrais-je ignorer ces performances potentiellement meilleures et toujours utiliser memmove
car cela ne garantit aucun chevauchement?
Le mot-clé ressortingct
est un conseil fourni au compilateur pour permettre la génération de code, indiquant au compilateur qu’il ne devrait pas être dérangé par la possibilité d’un alias de pointeur (deux pointeurs nommés différents accédant à la même adresse).
Dans une fonction qui prend ressortingct
pointeurs de ressortingct
, le compilateur comprend que l’écriture sur l’un n’aura pas d’impact sur l’autre. Lors de la copie d’un emplacement A à un emplacement B, cela signifie que vous pouvez modifier ce code en toute sécurité:
Dans cette séquence:
Ces deux séquences ne sont identiques que si A et B ne se chevauchent pas et que le compilateur n’optimisera pas la seconde sauf si vous avez utilisé ressortingct
(ou s’il ne peut pas deviner, à partir du contexte, qu’il est sécuritaire de le faire).
Si vous finissez par fournir un pointeur aliasé sur une fonction qui ne les attend pas, le compilateur pourra peut-être vous avertir au moment de la compilation, mais rien ne garantit qu’il le fera. Mais vous ne devriez vraiment pas vous attendre à une erreur au moment de la compilation – vous devriez plutôt la voir comme une permission que vous accordez au compilateur lorsqu’il génère l’assembly à partir de votre code.
Répondez à votre question sur les performances – si vous êtes certain que vos pointeurs ne se chevauchent pas, utilisez memcpy
. Si vous ne le faites pas, utilisez memmove
. memmove
générale, memmove
vérifie s’il y a un chevauchement et finit par utiliser memcpy
s’il memcpy
existe pas, mais vous payez le chèque.
La fonction
memcpy
copie n octets de la zone mémoire src vers la zone mémoire destinée directement .
Par “directement”, je suppose que vous voulez dire que la fonction évite de copier d’abord de la source à la mémoire tampon, puis de la mémoire tampon à la destination. Bien que cela soit vraisemblablement vrai, la norme n’exige pas qu’elle soit vraie.
memmove
utilise un tampon pourmemmove
tout risque de chevauchement de mémoire.
Non, memmove
produit un résultat comme s’il avait d’abord été copié dans un tampon, puis de là vers la destination. Il n’est pas nécessaire d’utiliser réellement un tampon de cette manière, à condition que le résultat souhaité soit obtenu. Toute implémentation donnée pourrait ou non le faire.
Est-
memcpy
quememcpy
utilise un pointeur indépendant? Parce que la sortie montre clairement un comportement indéfini et queressortingct
n’empêche pas l’access à la mémoire qui se chevauche avecmemcpy
.
ressortingct
n’empêche rien, jamais. Les compilateurs ne sont pas tenus de diagnostiquer ni même de remarquer que vous transmettez des pointeurs avec alias pour ressortingct
parameters qualifiés. En effet, cette détermination ne peut souvent pas être faite au moment de la compilation.
En effet, lorsque vous appelez memcpy()
avec les arguments que vous avez memcpy()
lors de votre premier appel, vous fournissez deux pointeurs indépendants vers le même object que les arguments source et destination. En conséquence, le comportement du programme n’est pas défini.
Votre programme présente également un comportement indéfini suite au calcul itself - 14
(que le pointeur obtenu soit ou non déréférencé). Si itself
lieu de cela itself
– itself
pointait au moins 14 octets à l’intérieur de l’object alloué, de sorte que l’arithmétique du pointeur soit valide, les arguments de la seconde commande memcpy()
seraient à nouveau incompatibles avec les exigences de la qualification ressortingct
des parameters le programme afficherait UB pour cette raison aussi.
Je suppose que
memcpy
a un avantage enmemcpy
performances puisqu’il copie directement les données, tandis quememmove
utilise un tampon. Mais avec les ordinateurs modernes, devrais-je ignorer ces performances potentiellement meilleures et toujours utilisermemmove
car cela ne garantit aucun chevauchement?
C’est une question d’opinion, et donc hors sujet ici. Je dirai seulement qu’il est préférable d’aborder les questions de performance en mesurant d’ abord, puis en prenant des décisions éclairées par les résultats de ces mesures. De plus, les caractéristiques de performance de différentes implémentations peuvent varier.
ressortingct
n’arrête jamais le comportement indéfini. En fait, il introduit un comportement non défini dans certains cas. Si ressortingct
est supprimé d’un morceau de code qui n’a pas d’UB, le code n’a toujours pas d’UB. mais l’inverse n’est pas vrai.
Votre code provoque un comportement indéfini sur cette ligne:
strcpy(itself, "Does ressortingct stop undefined behavior?");
en raison du débordement de la taille du tampon alloué. Après cela, tous les paris sont ouverts.
Le qualificatif de ressortingct
n’empêche pas les dépassements de mémoire tampon.