C/C++ [Bitwise] Get_base

Shornaal

Membre Actif
Inscrit
17 Février 2011
Messages
194
Reactions
0
#1
Salut,

Je suis tombé sur une fonction qui prend en paramètre un int n étant la taille d'une base (8 octales,16 héxa etc..) et en fait une sortie en string. Rien de fôlichon jusque là. Voici le code (Désolé je ne sais pas utiliser la coloration syntaxique:
Code:
char	*get_base(int n)
{
	int		i;
	char	*s;

	i = ~(!n);
	s = strnew(n + 1);
	while (++i < n)
		*(s + i) = (i < 10) ? ('0' + i) : ('A' + (i - 10));
	return (s);
}
Ma question comporte le ~(!n), si la valeur est positive il renvoi -1 grâce à l'overflow du i0nt non-signé et fait tourner la boucle, pas de soucis ! Façon un peu nerd d'initialiser sa variable pour faire "skills". Seulement si la valeur de n est à 0 alors, l'opération renvoit -2, comment on arrive à en inversant chaque bits de 0 ? Chaque bits en binaire n'est-il pas à zero ? Ca décalerait le pointeur de s - 1 soit.. Segfault ou bus error. Le mec qui a fait ça est une grosse tanche ou suis-je trop loin de la lumière pour comprendre les rois du bitwise ?
Ce ~(!n) m'énerve. Expliquez moi.

Des bisous !
 

Labo

Membre Actif
Inscrit
16 Aout 2013
Messages
799
Reactions
15
#2
C'est très simple en fait si on sait que !0==1 et que ~ est l'inversion de bits (à condition de connaître la notation des nombres en binaire).

On va ici prendre des entiers sur 4 bits, même si c'est pas réaliste ça me fait moins à taper.

Intéressons-nous au sens de l'opération suivante :
Code:
1111 + 1 = 0
En fait, si on avait pris des entiers sur 5 bits, ça aurait donné 10000. Il se trouve que la notation des nombres négatifs en complément à 2 est telle qu'on peut effectuer les additions de la même manière que si on avait plus de bits et qu'on tronquait ensuite.

Ainsi, puisqu'on a encore
Code:
x + ~x = 1111 (ou 11…1 selon le nombre de bits des entiers)
et qu'on a toujours
Code:
1111 + 1 = 0
alors
Code:
x + ~x = -1
C'est ainsi qu'on obtient :
Code:
~x = -x - 1 !
Ce n'est donc pas étonnant que
Code:
~(!0) = ~1 = -1 - 1 = -2
:D
Si tu veux le voir en écriture binaire (ici, 10 représente 2) :
Code:
~1 + 10 = 11…10 + 10 = 0
Pour voir un exemple non trivial d'utilisation d'une telle opération binaire, regarde le challenge 1 : http://www.cadernis.fr/viewtopic.php?f=34&t=1948

Enfin, la coloration syntaxique est disponible via un menu déroulant situé à droite du bouton URL dans l'éditeur avancé.
 

Shornaal

Membre Actif
Inscrit
17 Février 2011
Messages
194
Reactions
0
#3
Un grand merci Labo ! J'ai compris ton lien sur le complément à deux est plutôt pratique :p. L'école où je suis manque sérieusement de cours théorique et seul ce genre de question peut vite devenir tricky. En tout cas le mec est donc bien débile, ca risque de bus error ou segfault si la valeur passée en argument est invalide. J'imagine que du coup le comportement serait différent sur des unsigned et qu'on arriverait juste à la valeur max ?
 

Labo

Membre Actif
Inscrit
16 Aout 2013
Messages
799
Reactions
15
#4
Pas de quoi.
Je ne suis pas sûr de comprendre la fonction strnew, mais si c'est une sorte de malloc, je ne comprends pas non plus pourquoi il a besoin de n+1 cases alors qu'il utilise *(s+i) pour i dans [|0,n-1|]…
Je pense que le segfault est voulu vu qu'il n'existe pas de base 0.
Et en effet, c'est du très mauvais code, un simple n?(-1):(-2) aurait été beaucoup plus clair (je suis pas sûr de l'utilité des parenthèses, j'ai pas fait de C depuis longtemps). Ou même -1-!n si on veut utiliser le même nombre de caractères.

Ah et :
Shornaal a dit:
Sérieusement Labo je trouve ton poste limite. Déjà imposer son école dans le débat ça m'a toujours gavé mais delà à dire que le reste c'est des bricoles... Il n'y a pas de langage moins noble, juste des développeur qui ne sont pas capable de faire preuve d’adaptabilité.
Shornaal a dit:
L'école où je suis manque sérieusement de cours théorique et seul ce genre de question peut vite devenir tricky.
Just saying…
 
Inscrit
22 Octobre 2011
Messages
34
Reactions
0
#5
La convention en C c'est que les chaînes de caractères doivent terminer par un '\0', je suppose donc que strnew(n+1) doit faire un truc du genre allouer n + 1 cases mémoires initialisées à 0, et le reste du code s'occupe de remplir les n premières cases de la chaîne, la dernière étant laissée à 0.

Ah et: je crois qu'il y a une différence de sens entre la première et la deuxième "école" de Shornaal...
 

Shornaal

Membre Actif
Inscrit
17 Février 2011
Messages
194
Reactions
0
#6
Au-delà d'une simple convention c'est '\0' délimite la fin d'une chaine pour éviter que l'on puisse lire plus loin dans la mémoire et éviter l'overflow. Scalexm a aussi raison au niveau de l'école le sens du mot est dans les deux posts différents, le premier traite d'école genre courant de pensée, l'autre parle d'école endroit où l'on suit une formation. En tout cas je suis rassuré, le segfault en cas de cas d'erreur est débile. Merci pour la notion sur le NOT binaire en tout cas.
 
Inscrit
22 Octobre 2011
Messages
34
Reactions
0
#7
Oui et c'est bel et bien une convention. Il y aurait de nombreuses autres façons de délimiter la fin d'une chaîne de caractères, comme passer constamment la taille de la chaîne en argument, ou mieux transporter la chaîne et sa taille dans une structure. D'ailleurs, la plupart des autres langages n'utilisent pas la convention des null terminated strings.
 

Labo

Membre Actif
Inscrit
16 Aout 2013
Messages
799
Reactions
15
#8
Je sais pour l'école, je voulais relever l'ironie de la situation…
Il y a deux types de langages : ceux qui font des beaux programmes et ceux que je ne maîtrise pas.
 
Haut Bas