Pourquoi C n’a-t-il pas de littéraux binarys?

Je souhaite souvent pouvoir faire quelque chose comme ça en c:

val1 &= 0b00001111; //clear high nibble val2 |= 0b01000000; //set bit 7 val3 &= ~0b00010000; //clear bit 5 

Avoir cette syntaxe semble être un ajout incroyablement utile à C, sans aucun inconvénient auquel je puisse penser, et cela semble être une chose naturelle pour un langage de bas niveau où le bricolage est assez commun.

Edit: Je vois d’autres solutions intéressantes, mais elles s’effondrent chaque fois qu’il existe un masque plus complexe. Par exemple, si reg est un registre qui contrôle les broches d’E / S sur un microcontrôleur et que je souhaite définir les broches 2, 3 et 7 en même temps, je pourrais écrire reg = 0x46; mais je devais passer 10 secondes à y penser (et je devrai probablement passer 10 secondes à chaque fois que je lirai ce code après ne pas l’avoir lu pendant un jour ou deux) ou je pourrais écrire reg = (1 << 1) | (1 << 2) | (1 << 6); reg = (1 << 1) | (1 << 2) | (1 << 6); mais personnellement, je pense que c’est beaucoup moins clair que d’écrire ‘reg = 0b01000110;’ Je peux convenir que cela ne va pas bien au-delà des architectures 8 bits ou peut-être 16 bits. Non pas que j’ai jamais eu besoin de faire un masque 32 bits.

Conformément à la justification pour la norme internationale Standard – Langages de programmation C §6.4.4.1 Constantes de nombre entier

Une proposition visant à append des constantes binarys a été rejetée faute de précédent et d’utilité insuffisante.

Ce n’est pas en C standard, mais GCC le supporte comme une extension, préfixée par 0b ou 0B :

  i = 0b101010; 

Voir ici pour plus de détails.

C’est ce qui a poussé hexadécimal à être … hexadécimal. Le “… principal usage de la notation hexadécimale est une représentation conviviale des valeurs codées binarys en informatique et en électronique numérique … “. Ce serait comme suit:

 val1 |= 0xF; val2 &= 0x40; val3 |= ~0x10; 

Hexadécimal:

  1. Un chiffre hexadécimal peut représenter un quartet (4 bits ou un demi octal).
  2. Deux chiffres hexadécimaux peuvent représenter un octet (8 bits).
  3. Hex est beaucoup plus compact lors de la mise à l’échelle de masques plus grands.

Avec un peu de pratique, la conversion entre hexadécimal et binary deviendra beaucoup plus naturelle. Essayez d’écrire vos conversions à la main sans utiliser de convertisseur de notation bin / hex en ligne. Dans quelques jours, cela deviendra naturel (et donc plus rapide).

De plus: Même si les littéraux binarys ne sont pas un standard C, si vous comstackz avec GCC, il est possible d’utiliser des littéraux binarys, ils doivent être précédés de «0b» ou «0B». Voir la documentation officielle ici pour plus d’informations. Exemple:

 int b1 = 0b1001; // => 9 int b2 = 0B1001; // => 9 

Tous vos exemples peuvent être écrits encore plus clairement:

 val1 &= (1 << 4) - 1; //clear high nibble val2 |= (1 << 6); //set bit 6 val3 &=~(1 << 3); //clear bit 3 

(J'ai pris la liberté de fixer les commentaires à compter de zéro, comme le voulait la nature.)

Votre compilateur pliera ces constantes, il n'y a donc aucune pénalité de performance à les écrire de cette façon. Et ceux-ci sont plus faciles à lire que les versions 0b...

Je pense que la lisibilité est une préoccupation primordiale. Bien que de bas niveau, ce sont les êtres humains qui lisent et maintiennent votre code, pas la machine.

Est-il facile pour vous de savoir que vous avez saisi par erreur 0b1000000000000000000000000000000(0x40000000) , où vous voulez vraiment dire 0b10000000000000000000000000000000(0x80000000) ?

“Par exemple, si reg est un registre qui contrôle les broches d’E / S sur un microcontrôleur”

Je ne peux pas m’empêcher de penser que c’est un mauvais exemple. Les bits dans les registres de contrôle ont des fonctions spécifiques (comme tous les dispositifs connectés à des bits IO individuels).

Il serait beaucoup plus judicieux de fournir des constantes symboliques pour les modèles de bits dans un fichier d’en-tête, plutôt que de définir le binary dans le code. La conversion de données binarys en valeurs hexadécimales ou octales est simple, se rappeler de ce qui se passe lorsque vous écrivez 01000110 dans un registre IO ne l’est pas, en particulier si vous n’avez pas la fiche technique ou le schéma de circuit.

Vous ne sauvegarderez donc pas seulement ces 10 secondes d’essai de calcul du code binary, mais peut-être un peu plus de temps à essayer de déterminer ce qu’il fait!

Si vous n’avez pas besoin d’un littéral réel, vous pouvez faire quelque chose comme ceci:

 #define B_(x) strtoull(#x, 0, 2) unsigned char low_nibble = B_(00001111); unsigned char bit_7 = B_(01000000); unsigned char bit_5 = B_(00010000); val1 |= low_nibble; val2 &= bit_7; val3 |= ~bit_5; 

Si vous insistez sur les constantes de temps de compilation, ce qui suit n’est pas aussi général, mais fonctionne pour 8 bits.

 #define B0_(X) ((X) % 8 + B1_((X)/8) * 2) #define B1_(X) ((X) % 8 + B2_((X)/8) * 2) #define B2_(X) ((X) % 8 + B3_((X)/8) * 2) #define B3_(X) ((X) % 8 + B4_((X)/8) * 2) #define B4_(X) ((X) % 8 + B5_((X)/8) * 2) #define B5_(X) ((X) % 8 + B6_((X)/8) * 2) #define B6_(X) ((X) % 8 + B7_((X)/8) * 2) #define B7_(X) ((X) % 8) #define B_(x) B0_(0##x)