Je veux copier un tableau int sur un autre tableau int. Ils utilisent la même définition pour la longueur afin qu'ils soient toujours de la même longueur.
Quels sont les avantages/inconvénients des deux alternatives suivantes du paramètre de taille à memcpy ()?
memcpy(dst, src, ARRAY_LENGTH*sizeof(int));
ou
memcpy(dst, src, sizeof(dst));
La deuxième option fonctionnera-t-elle toujours? Indépendamment du contenu?
Une chose qui favorise le dernier est que si le tableau devait changer, ce serait un peu de ménage pour mettre à jour le memcpy ().
Merci
Tant que dst
est déclaré en tant que tableau avec une taille, sizeof
renverra la taille de ce tableau en octets:
int dst[ARRAY_LENGTH];
memcpy( dst, src, sizeof(dst) ); // Good, sizeof(dst) returns sizeof(int) * ARRAY_LENGTH
Si dst
est juste un pointeur sur le premier élément d'un tel tableau (qui est du même type que le tableau lui-même), cela ne fonctionnera pas:
int buffer[ARRAY_LENGTH];
int* dst = &buffer[0];
memcpy( dst, src, sizeof(dst) ); // Bad, sizeof(dst) returns sizeof(int*)
Si et quand vous avez un tableau (réel), vous pouvez utiliser l’astuce sizeof(array)
, mais notez que si vous refactorisez le code et que vous le poussez à un endroit où le tableau a été décomposé en un pointeur (ou si la mémoire a été initialement allouée dans un pointeur ( malloc/new), vous devrez passer une taille connue.
En ignorant les tailles relatives de la source et de la destination, c'est-à-dire en supposant qu'elles sont identiques pour le reste de la discussion, si vous utilisez le C++, je recommanderais une astuce de métaprogrammation qui vous donnera un nombre de tailles de type sécurisé pour les tableaux et échouera. compiler si vous essayez de l’utiliser avec des pointeurs:
template <typename T, int N>
inline int array_memory_size( T (&a)[N] ) { return sizeof a; }
De cette façon:
int main() {
int array[10];
int *ptr = array;
int orig[10] = { 0 };
memcpy( array, orig, array_memory_size(array) ); // ok
//memcpy( ptr, orig, array_memory_size(ptr) ); // compilation error
}
Si, à un moment quelconque, vous refactorisez et que le code se déplace vers un emplacement où le tableau s'est décomposé (ou si vous remplacez un tableau statique par un autre alloué dynamiquement), le compilateur vous indiquera que vous devez corriger le calcul de la taille.
sizeof(dst)
est correct uniquement si dst
est un tableau de taille connue au moment de la compilation: comme int arr[ARRAY_LENGTH]
ou un tableau de longueur variable C99; sinon, il retourne la taille d'un pointeur, pas la longueur du tableau de destination.
Pour éviter les bogues futurs, soyez cohérent et préférez la première forme: taille de type * longueur.
La deuxième option fonctionnera-t-elle toujours? Indépendamment du contenu?
La 2ème option ne fonctionne que si vous rajoutez le )
manquant et dst
est un tableau statique (c'est-à-dire de type int[123]
).
Si dst
a une taille inconnue (c'est-à-dire int[]
), alors sizeof dst
ne renvoie que la taille du pointeur, car dst
a été décomposé en pointeur. Dans ce cas, vous devez utiliser sizeof(*dst)*ARRAY_LENGTH
.
Si vous avez alloué en utilisant malloc, vous devez indiquer la taille du tableau
int * src = malloc(ARRAY_LENGTH*sizeof(*src));
int * dst1 = malloc(ARRAY_LENGTH*sizeof(*dst));
memcpy(dst1,src,ARRAY_LENGTH*sizeof(*dst));
Si vous avez alloué un tableau statique, vous pouvez simplement utiliser sizeof
int dst2[ARRAY_LENGTH];
memcpy(dst2,src,sizeof(dst2));
La deuxième option fonctionnera-t-elle toujours? Indépendamment du contenu?
Cela ne fonctionnera que si les deux conditions sont remplies:
dst
est un tableau normal, pas un pointeursrc
et dst
ont la même taillesizeof (X) vous donne toujours le nombre de bytes de "X" si X est un tableau uint16_t de 10, alors sizeof (X) retournera 20
uint16_t X[10]={0};
cout<<"sizeof x: "<<sizeof(X);
$> sizeof x: 20
si vous voulez le nombre d'éléments, vous devez faire un peu d'arithmétique sur les octets:
8bit = 1 octet
16bit = 2 octets
32bit = 4 octets
64bit = 8 octets
pour avoir le nombre d’éléments que vous pouvez faire:
numb_of_elements = ( sizeof(X)/sizeof(X[0]) );
résultant en:
uint32_t source[100]={0};
memcpy((void*) dest, (void*) source, ( sizeof(source)/sizeof(source[0]) ));
bien sûr, vous voudrez probablement faire (sizeof (X)/sizeof (X [0])) une constante/variable pour que vous ne calculiez pas à chaque fois .. (je ne sais pas si les compilateurs optimiseront toujours cela)
En supposant que dst soit de type int *, sizeof (dst) retournera la taille du pointeur lui-même (c'est-à-dire 4 sur un système 32 bits, 8 sur un système 64 bits). le premier utilisera correctement la taille réelle du contenu.
Ça dépend. Arr et le pointeur sont des tableaux, mais sizeof () ne renvoie que la taille correcte pour arr, qui est déclaré à la compilation.
int main() {
int arr[10];
int * pointer;
pointer = (int *) malloc(10 * sizeof(int));
printf("%d\n", sizeof(arr)); // 40
printf("%d\n", sizeof(pointer)); // 4 or 8
free(pointer);
}
Si dst a été alloué depuis le tas (en utilisant malloc par exemple), la deuxième solution ne fonctionnera pas. sizeof (dst) ne fonctionnera que s’il est connu du compilateur. Par exemple, l'exemple suivant échouera car sizeof (dst) sera égal à la taille d'un pointeur (4-8 octets).
#define ARRAY_LENGTH 10
int *dst;
dst = malloc(ARRAY_LENGTH*sizeof(int));
memcpy(dst, src, sizeof(dst)); // sizeof dst in this case would be 4 bytes on 32 bit system
Ce segment de code fonctionnera à chaque fois:
#define ARRAY_LENGTH 10
int *dst;
dst = malloc(ARRAY_LENGTH*sizeof(int));
memcpy(dst, src, ARRAY_LENGTH*sizeof(int)); // sizeof would be 40 bytes
Que diriez-vous?
memcpy(dst, src, &src[ARRAY_LENGTH] - &src[0]);
Cela devrait fonctionner même si la taille des éléments individuels était inférieure à la taille prise par chaque élément du tableau actuel.
memcpy (), quelle devrait être la valeur du paramètre de taille?
Ce doit être le minimum entre la taille du tampon source et la taille du tampon de destination.
Traditionnellement, la taille du tampon source a été utilisée. Cela a occasionnellement débordé du tampon de destination ... Il est donc préférable d’utiliser une version "plus sûre" de la fonction: une version qui spécifie à la fois la taille des tampons source et de destination.
Vous avez des fonctions "plus sûres" disponibles via ISO/IEC TR24731 . Il y a beaucoup plus que cela, comme des valeurs de retour cohérentes et un comportement cohérent de traitement des chaînes.
Les fonctions "plus sûres" font maintenant partie de la norme C, donc supposées être disponibles partout. Donc, vous devriez utiliser memcpy_s
.
Vous ne pouvez pas l'utiliser sous Linux, car il ne fournit pas les fonctions (ne croyez pas le battage publicitaire concernant les normes conformes)). Sous Linux, vous devriez "rouler votre propre" wrapper.
Tout le monde n'est pas fan des fonctions plus sûres. Voir, par exemple, Utilisez-vous les fonctions «safe» du TR 24731? . Tout ce que je peux dire à ce sujet est: Plusieurs débordements de tampon libunp . Des millions de routeurs et de passerelles sont soumis à de multiples vulnérabilités et beaucoup restent non corrigés. Et ils étaient dus à des bugs qui auraient été arrêtés par les fonctions plus sûres. +1 à tous ceux qui disent "n'utilisez pas cette merde de Microsoft".