Aller au contenu

%BITXOR

OU exclusif bit à bit

Compare deux valeurs bit par bit et met à 1 les bits qui diffèrent : sert à basculer un indicateur, à repérer ce qui a changé entre deux états ou à masquer une donnée de façon réversible.

Syntaxe

%BITXOR(expression1 : expression2)
expression1, expression2
Les deux valeurs à comparer : des entiers ou des zones caractère.
Résultat
Pour des entiers : le nombre dont les bits sont à 1 quand ils diffèrent entre les deux opérandes. Pour des zones caractère : une chaîne de la longueur du plus long opérande, calculée octet par octet.

À quoi ça sert

Le OU exclusif a deux usages courants. D'abord basculer un bit : appliquer le même masque deux fois remet la valeur d'origine, comme un interrupteur. Ensuite comparer : le résultat vaut 0 si les deux valeurs sont identiques, et ses bits à 1 indiquent exactement ce qui a changé.

Il sert aussi à un masquage simple et réversible d'une donnée avec une clé : c'est de l'offuscation, pas du chiffrement.

Exemple 1 : Basculer un droit et repérer les différences

**free
// %BITXOR : inverser un droit (interrupteur) et trouver ce qui differe entre deux mots.
ctl-opt dftactgrp(*no) actgrp(*new);

dcl-c ECRITURE 2;

dcl-s droits  uns(10) inz(3);      // lecture + ecriture
dcl-s avant   uns(10) inz(3);
dcl-s apres   uns(10) inz(6);      // ecriture + suppression

snd-msg 'Depart          : [' + %char(droits) + ']';

droits = %bitxor(droits : ECRITURE);
snd-msg 'Bascule ecriture: [' + %char(droits) + ']';

droits = %bitxor(droits : ECRITURE);
snd-msg 'Bascule encore  : [' + %char(droits) + ']';

// Les bits qui ont change entre deux etats : 3 -> 6
snd-msg 'Differences     : [' + %char(%bitxor(avant : apres)) + ']';

// Deux valeurs identiques donnent zero
snd-msg 'Identiques      : [' + %char(%bitxor(apres : apres)) + ']';

*inlr = *on;

Résultat réel, compilé et exécuté sur IBM i 7.5 :

Depart          : [3]
Bascule ecriture: [1]
Bascule encore  : [3]
Differences     : [5]
Identiques      : [0]

Le mot de droits vaut 3 (lecture et écriture). Un premier %bitxor avec 2 retire l'écriture (1), un second la remet (3). Entre les états 3 et 6, le résultat 5 indique que les bits de valeur 1 et 4 ont changé. Deux valeurs identiques donnent 0.

Exemple 2 : Masquage réversible d'une zone

**free
// %BITXOR sur des zones caracteres : OU exclusif octet par octet.
ctl-opt dftactgrp(*no) actgrp(*new);

// API C standard : convertit des octets en texte hexadecimal
dcl-pr cvthc extproc('cvthc');
  cible pointer value;
  source pointer value;
  longueur int(10) value;
end-pr;

dcl-s message char(4) inz('ABCD');
dcl-s cle     char(4) inz(x'5A5A5A5A');
dcl-s codee   char(4);
dcl-s clair   char(4);
dcl-s res3    char(3);

// Masquage reversible : appliquer deux fois la meme cle redonne l'original
codee = %bitxor(message : cle);
snd-msg 'Codee (hex)     : ' + hex(%addr(codee) : 4);
clair = %bitxor(codee : cle);
snd-msg 'Redecodee       : [' + clair + ']';

// Longueurs differentes
res3 = %bitxor(x'FFFFFF' : x'0F');
snd-msg 'FFFFFF ^ 0F     : ' + hex(%addr(res3) : 3);

*inlr = *on;

dcl-proc hex;
  dcl-pi *n varchar(16);
    adresse pointer value;
    longueur int(10) value;
  end-pi;
  dcl-s texte char(16);
  cvthc(%addr(texte) : adresse : longueur * 2);
  return %subst(texte : 1 : longueur * 2);
end-proc;

Résultat réel, compilé et exécuté sur IBM i 7.5 :

Codee (hex)     : 9B98999E
Redecodee       : [ABCD]
FFFFFF ^ 0F     : F0FFFF

Le texte ABCD passé par le OU exclusif avec la clé 5A5A5A5A donne des octets illisibles (9B98999E en hexadécimal, les lettres étant codées en EBCDIC). Le même calcul avec la même clé redonne ABCD. La dernière ligne montre que, pour des longueurs différentes, les octets sans vis-à-vis sont recopiés tels quels (FFFFFF et 0F donnent F0FFFF).

Le piège

Les octets en trop ne sont pas remis à zéro. Avec des opérandes de longueurs différentes, on pourrait croire que le plus court est complété par des zéros et que le résultat s'annule au-delà : %bitxor(x'FFFFFF' : x'0F') renvoie F0FFFF, les deux derniers octets de la première valeur sont conservés. Alignez les longueurs si ce n'est pas le comportement voulu.