Définition d’un tampon de char * avec une diffusion intermédiaire sur int *

Je ne pouvais pas bien comprendre les conséquences de ce que je lis ici: Lancer un pointeur int sur un caractère ptr et vice versa

En bref, cela fonctionnerait-il?

set4Bytes(unsigned char* buffer) { const uint32_t MASK = 0xffffffff; if ((uintmax_t)buffer % 4) {//misaligned for (int i = 0; i < 4; i++) { buffer[i] = 0xff; } } else {//4-byte alignment *((uint32_t*) buffer) = MASK; } } 

modifier
Il y a eu une longue discussion (c’était dans les commentaires, qui ont été mystérieusement supprimés) sur le type de pointeur à utiliser pour vérifier l’alignement. Le sujet est maintenant abordé ici .

Cette conversion est sûre si vous remplissez la même valeur dans les 4 octets . Si l’ byte order important, cette conversion n’est pas sûre. Parce que lorsque vous utilisez un entier pour remplir 4 octets à la fois, il remplira 4 Bytes mais l’ordre dépend de l’ endianité .

Ce code pourrait vous être utile. Il montre un numéro 32 bits en cours de construction en atsortingbuant à son contenu un octet à la fois, ce qui entraîne un désalignement. Il comstack et travaille sur ma machine.

 #include #include #include #include int main () { uint32_t *data = (uint32_t*)malloc(sizeof(uint32_t)*2); char *buf = (char*)data; uintptr_t addr = (uintptr_t)buf; int i,j; i = !(addr%4) ? 1 : 0; uint32_t x = (1<<6)-1; for( j=0;j<4;j++ ) buf[i+j] = ((char*)&x)[j]; printf("%" PRIu32 "\n",*((uint32_t*) (addr+i)) ); } 

Comme mentionné par @Learner, il faut obéir à l’endianisme. Le code ci-dessus n'est pas portable et se briserait sur une machine big endian.

Notez que mon compilateur renvoie l'erreur "transtyper de 'char *' à 'unsigned int' perd la précision [-fpermissive]" lors de la tentative de transtypage d'un char * vers un unsigned int, comme dans le message d'origine. Cet article explique que uintptr_t devrait être utilisé à la place.

Non, ça ne marchera pas dans tous les cas. En plus de l’endianisme, qui peut poser problème ou non, vous supposez que l’alignement de uint32_t est 4. Toutefois, cette quantité est définie par la mise en œuvre (C11 Draft N1570, section 6.2.8). Vous pouvez utiliser l’opérateur _Alignof pour obtenir l’alignement de manière portable.

Deuxièmement, le type effectif ( ibid. Sec. 6.5) de l’emplacement désigné par buffer peut ne pas être compatible avec uint32_t (par exemple, si buffer pointe sur un tableau de caractères unsigned char ). Dans ce cas, vous enfreignez les règles de crénelage ssortingctes lorsque vous essayez de lire le tableau lui-même ou un pointeur de type différent.

En supposant que le pointeur pointe réellement sur un tableau de caractères unsigned char , le code suivant fonctionnera

 typedef union { unsigned char chr[sizeof(uint32_t)]; uint32_t u32; } conv_t; void set4Bytes(unsigned char* buffer) { const uint32_t MASK = 0xffffffffU; if ((uintptr_t)buffer % _Alignof(uint32_t)) {// misaligned for (size_t i = 0; i < sizeof(uint32_t); i++) { buffer[i] = 0xffU; } } else { // correct alignment conv_t *cnv = (conv_t *) buffer; cnv->u32 = MASK; } } 

Outre le problème final , qui a déjà été mentionné ici:

CHAR_BIT – le nombre de bits par caractère – doit également être pris en compte.

Il est 8 sur la plupart des plates-formes, où for (int i=0; i<4; i++) devrait fonctionner correctement.

Une façon plus sûre de le faire serait for (int i=0; i .

Vous pouvez également inclure et utiliser for (int i=0; i<32/CHAR_BIT; i++) .

Utilisez reinterpret_cast<>() si vous voulez vous assurer que les données sous-jacentes ne “changent pas de forme”.

Comme le dit l’apprenant, lorsque vous stockez des données dans la mémoire de la machine, l’ endurance devient un facteur. Si vous savez comment les données sont correctement stockées en mémoire (endianess correcte) et que vous testez spécifiquement leur présentation en tant que représentation alternative, vous pouvez utiliser reinterpret_cast<>() pour tester cette mémoire, en tant que type spécifique, sans modification. le stockage d’origine.

Ci-dessous, j’ai modifié votre exemple pour utiliser reinterpret_cast<>() :

 void set4Bytes(unsigned char* buffer) { const uint32_t MASK = 0xffffffff; if (*reinterpret_cast(buffer) % 4) {//misaligned for (int i = 0; i < 4; i++) { buffer[i] = 0xff; } } else {//4-byte alignment *reinterpret_cast(buffer) = MASK; } } 

Il convient également de noter que votre fonction semble définir le tampon (mémoire sur 32 octets) à 0xFFFFFFFF, quelle que soit la twig prise.

Votre code est parfait pour travailler avec toutes les architectures 32 bits et plus. Il n’y a aucun problème avec la commande d’octet puisque tous vos octets source sont 0xFF .

Sur les machines x86 ou x64, le travail supplémentaire nécessaire pour traiter les access éventuellement non alignés à la RAM est géré par le CPU et transparent pour le programmeur (depuis Pentium II), avec un coût de performance à chaque access. Donc, si vous ne définissez que les quatre premiers octets d’un tampon plusieurs fois, il est bon de simplifier votre fonction:

 void set4Bytes(unsigned char* buffer) { const uint32_t MASK = 0xffffffff; *((uint32_t *)buffer) = MASK; } 

Quelques lectures:

  1. Un document du kernel Linux sur les access mémoire non alloués
  2. Manuel d’optimisation de l’architecture Intel, section 3.4
  3. Alignement de données Windows sur IPF, x86 et x64
  4. Un access pratique ‘à la mémoire alignée ou non alignée ‘, par Alexander Sandler