Pourquoi utiliser memcpy () quand vous pouvez passer directement des pointeurs pour fonctionner en C?

avinal

Ceci fait partie du code source de l'utilitaire de cryptage de fichiers BCrypt. Inchangé, sauf quelques commentaires que j'ai ajoutés.

uLong BFEncrypt(char **input, char *key, uLong sz, BCoptions *options) {
  uInt32 L, R;
  uLong i;
  BLOWFISH_CTX ctx;
  int j;
  unsigned char *myEndian = NULL;
  j = sizeof(uInt32);

  getEndian(&myEndian);

// makes space 2 bytes
  memmove(*input+2, *input, sz);

// add endian and compresssion option
  memcpy(*input, myEndian, 1);
  memcpy(*input+1, &options->compression, 1);

  sz += 2;    /* add room for endian and compress flags */ // total size increased

  Blowfish_Init (&ctx, key, MAXKEYBYTES); // initialize 

// encrypt the file
  for (i = 2; i < sz; i+=(j*2)) {   /* start just after tags */
    memcpy(&L, *input+i, j);// copy j bytes from input to L
    memcpy(&R, *input+i+j, j); // copy second j byte to R
    Blowfish_Encrypt(&ctx, &L, &R); // encrypt
    memcpy(*input+i, &L, j); // copy everything back
    memcpy(*input+i+j, &R, j);
  }

  if (options->compression == 1) {
    if ((*input = realloc(*input, sz + j + 1)) == NULL)
      memerror();

    memset(*input+sz, 0, j + 1);
    memcpy(*input+sz, &options->origsize, j);
    sz += j;  /* make room for the original size      */
  }

  free(myEndian);
  return(sz);
}

Dans la boucle, nous copions d'abord le tampon de fichier octet par octet vers de nouvelles variables, puis nous appliquons le cryptage Blowfish. Et puis à nouveau en copiant les octets dans le tampon. Pourquoi ne puis-je pas passer d'octets directement à la fonction de cryptage? Pourquoi memcpy()est même nécessaire?

Eric Postpischil

Pourquoi ne puis-je pas passer d'octets directement à la fonction de cryptage?

Il y a deux règles contre cela, ou du moins ne pas l'appuyer.

La première est que la conversion d'un pointeur en charpointeur en un inta un comportement indéfini si l'alignement n'est pas correct pour an intet, même si l'alignement est correct, la valeur du résultat n'est pas entièrement définie. Les règles à ce sujet se trouvent dans C 2018 6.3.2.3, qui couvre les conversions de pointeurs.

Généralement, les objets tels que intdoivent être situés à des multiples de quatre octets. Ceci est dû à la façon dont la mémoire de l'ordinateur et le bus de données sont organisés; les différents «fils» impliqués sont mis en place pour transférer les choses en groupes de certaines tailles et alignements. Lorsque le compilateur d'un tel système génère des instructions pour travailler avec des intobjets, il génère des instructions qui chargent des mots alignés. Si vous prenez un charpointeur qui n'est pas aligné et que vous le convertissez en pointeur vers int, certains processeurs génèrent une interruption lorsqu'une instruction de mot aligné de charge tente d'utiliser une adresse non alignée. D'autres processeurs peuvent ignorer les bits bas de l'adresse et charger un mot aligné à partir d'une adresse différente.

Même si l'adresse est alignée, la norme C ne garantit pas le résultat de la conversion de a char *en un int *pointant réellement vers le même endroit que l'original. En effet, dans certains systèmes, pour la plupart archaïques maintenant, les pointeurs vers différents types étaient représentés de différentes manières. Certains systèmes accèdent à la mémoire uniquement en mots de plusieurs octets, donc, pour implémenter char *, un compilateur doit synthétiser des adresses différentes des adresses matérielles, alors que, pour int *, un compilateur peut utiliser l'adresse matérielle directement.

La deuxième règle est que la mémoire désignée pour être utilisée pour un type, tel qu'un tableau de char, ne peut pas être librement utilisée comme un autre type, tel que int. Cette règle se trouve dans C 2018 6.5 7. Elle a des situations spécifiques qui sont autorisées, telles que n'importe quel type, tel que intou float, peut être consulté en tant que char, mais pas l'inverse. Le but de cette règle est qu'une routine ayant passé un int *iet un float *fpeut savoir que dans un code comme celui-ci:

for (int j = 0; j < 1024; ++j)
    f[j] += *i;

le f[j]accède toujours à a floatet n'accède jamais à un int, donc le corps de cette boucle ne change jamais la valeur de *i. Cela signifie que le compilateur peut optimiser le code pour:

int t = *i;
for (int j = 0; j < 1024; ++j)
    f[j] += t;

qui sauve le travail de chargement répété *ide la mémoire, parce que l'objet temporaire tpeut être conservé dans un registre de processeur. (En plus de cela, le compilateur pourrait effectivement utiliser float t = *i;, économisant à la fois le chargement répété de *idepuis la mémoire et la conversion répétée en floatpour l'ajout.)

Vous pouvez regarder cette motivation, puis regarder Blowfish_Encryptet voir que BlowFish_Encryptcette optimisation potentielle ne profite jamais de cette optimisation potentielle, peut-être parce qu'elle ne fonctionne jamais avec des types mixtes qui seraient affectés par cette règle. Cependant, la complexité des optimisations du compilateur devient plus difficile à voir à mesure que les compilateurs deviennent de plus en plus avancés et agressifs dans leurs transformations, il est donc facile de manquer un avantage que le compilateur tirera de la règle sur l'aliasing d'un type comme un autre. Dans tous les cas, comme la règle existe, vous n'avez aucune garantie que votre programme fonctionnera si vous la violez.

Cet article est collecté sur Internet, veuillez indiquer la source lors de la réimpression.

En cas d'infraction, veuillez [email protected] Supprimer.

modifier le
0

laisse moi dire quelques mots

0commentaires
connexionAprès avoir participé à la revue

Articles connexes

Lorsque vous travaillez avec des pointeurs en C, quand et pourquoi devons-nous utiliser malloc ?

Pourquoi et quand utiliser des pointeurs en C ?

Pourquoi utiliser !== quand vous pouvez utiliser === ?

Pointeurs C, comprendre comment passer des tableaux pour fonctionner

Passer des valeurs directement sous forme de tableau pour fonctionner en C

Pourquoi utiliser des génériques quand vous ne pouvez utiliser que des types

Passer un vecteur de pointeurs pour fonctionner en c++

Pourquoi utiliser des pointeurs en C?

Comment pouvez-vous utiliser getline pour saisir des valeurs dans des classes en C ++?

Quand utiliser des pointeurs

Pourquoi utiliser la fonction pour obtenir une propriété d'objets lorsque vous pouvez y accéder directement ?

Pointeurs de fonction - pourquoi, quand je peux m'en passer?

Pourquoi utiliser des rappels lorsque vous pouvez simplement appeler des fonctions globalement en Javascript ?

En C ++, pouvez-vous créer un objet comme argument pour fonctionner?

Vous ne pouvez pas utiliser + = en c #?

Pourquoi ne pouvez-vous pas utiliser l'initialisation d'accolades C ++ 11 avec des macros?

Pourquoi ne pouvez-vous pas utiliser un littéral 'f' directement après un entier ?

Pourquoi ne pouvez-vous pas passer des constructeurs de données comme des fonctions normales en OCaml ?

Pouvez-vous utiliser une propriété JSON nommée pour passer un objet complexe à un contrôleur C #?

Pourquoi pouvez-vous utiliser des variables de liste pour l'indexation mais pas une liste littérale ?

Quand devriez-vous utiliser des méthodes Get et appeler directement des variables?

Pouvez-vous oublier Checked-Delete lorsque vous utilisez des pointeurs intelligents C ++ 11?

Pouvez-vous utiliser emacs pour programmer en lisp commun?

Pourquoi et quand devrions-nous utiliser un pointeur vers un pointeur au lieu de simples pointeurs en C?

Comment pouvez-vous utiliser des paramètres facultatifs en C #?

Quand devriez-vous utiliser des fonctions sur des foncteurs en C ++?

Pouvez-vous utiliser des pandas pour parcourir une trame de données tout en multipliant la ligne précédente par une valeur ?

C Passer et réutiliser des pointeurs dans les fonctions

Comment utiliser des pointeurs pour imprimer des variables avec des structures en C?

TOP liste

  1. 1

    Filtrer le dataframe basé sur plusieurs colonnes d'un autre dataframe

  2. 2

    Laravel SQLSTATE [HY000] [1049] Base de données inconnue 'previous_db_name'

  3. 3

    Enregistrer le chemin de l'image de la galerie vers la base de données de la salle et l'afficher dans la liste des recycleurs

  4. 4

    Comment afficher du texte au milieu de div avec une couleur d'arrière-plan différente?

  5. 5

    Microsoft.WebApplication.targets

  6. 6

    Comment changer le navigateur par défaut en Microsoft Edge pour Jupyter Notebook sous Windows 10 ?

  7. 7

    Échec de l'exécution de 'insertBefore' sur 'Node': le paramètre 1 n'est pas de type 'Node'

  8. 8

    Empêcher l'allocation de mémoire dans la génération de combinaison récursive

  9. 9

    Comment analyser un fichier avec un tableau d'objets JSON en utilisant Node.js?

  10. 10

    comment afficher un bouton au-dessus d'un autre élément ?

  11. 11

    Comment centrer un div tout en utilisant la transition et transformer avec l'échelle

  12. 12

    Filtrer les données en fonction des conditions d'une trame de données

  13. 13

    ESP8266 HADRWARE MINUTERIE, USA pour cocher une macro étrange

  14. 14

    Comment définir du texte dans un QLabel et afficher les caractères '<>'?

  15. 15

    System.Data.SqlClient.SqlException: 'Nom de colonne non valide' ApplicationRoleId '.'

  16. 16

    Pourquoi Phantomjs ne fonctionne pas avec ce site ?

  17. 17

    Stop jQuery execution after one time execution

  18. 18

    Concaténer des variables dans ansible

  19. 19

    Comment calculer la probabilité du graphique de densité?

  20. 20

    php ajouter et fusionner des données de deux tables

  21. 21

    Redirection HTTP vers HTTPS dans Java à l'aide de HTTPURLConnection

chaudétiquette

Archive