Je pense que c'est juste une façon amusante de définir VRAI comme 1 et FAUX comme 0
BlackDwarf
160
Notez que c'est une idée terrible sans crochets autour de ces expressions. Je veux dire que c'est une idée terrible avec eux, mais sans vous demandez juste une longue nuit de débogage.
TartanLlama
70
Puis-je connaître le livre de codage auquel vous faites référence?
artm
47
J'espère que ce livre l'a inclus comme exemple de code mauvais ou délibérément obscur.
Jon Hanna du
31
@Daniel: Une autre idée serait que rand ()% 2 définisse MAYBE comme rand ()% 2, c'est-à-dire parfois == VRAI et parfois == FAUX.
Kaiserludi
Réponses:
380
Voyons voir: '/' / '/'signifie le charlittéral /, divisé par le charlittéral '/'lui-même. Le résultat est un, ce qui semble raisonnable TRUE.
Et '-' - '-'signifie le charlittéral '-', soustrait de lui-même. C'est zéro ( FALSE).
Il y a deux problèmes avec cela: d'abord, ce n'est pas lisible. Utilisation 1et 0est absolument mieux. De plus, comme TartanLlama et KerrekSB l'ont souligné, si vous prévoyez d'utiliser cette définition, veuillez ajouter des parenthèses autour d'eux afin de ne pas avoir de surprise:
Cela affichera la valeur du charlittéral '-'(45 sur mon système).
Avec des parenthèses:
#define TRUE ('/'/'/')#define FALSE ('-'-'-')
le programme imprime correctement zéro, même si cela n'a pas beaucoup de sens de multiplier une valeur de vérité par un entier, mais ce n'est qu'un exemple du genre de bogues inattendus qui pourraient vous mordre si vous ne mettez pas vos macros entre parenthèses.
Merde, j'ai pris beaucoup de temps pour le comprendre: je pensais même que c'était une chose étrange en tant que glyphes ... je ne sais pas xD
Luis Masuelli
8
Il est en fait logique de multiplier par la valeur de vérité. Par exemple, l'indentation * should_indent entraînera soit 0 soit une indentation selon que should_indent sans branchement. (Je suppose que c'est un mauvais exemple, lorsque travailler avec une seule branche de texte n'a pas d'importance (j'ai vu cette technique dans les shaders et dans XPATH (tous deux trop différents et je ne me souviens pas de la forme exacte))
Alpedar
2
Alpedar - mais cela n'a pas de sens conceptuel et matériel de le faire - dans ce cas, il serait plus clair (et conceptuellement logique) d'utiliser un ifau lieu de le multiplier TRUEpar un entier.
Jay
4
Grande explication. Ayez un badge en or!
Michael Hampton
2
La négation logique peut être implémentée au fur notx = TRUE- x;et à mesure . Sauf que TRUE-FALSEc'est -44 (en supposant ASCII)
Hagen von Eitzen
89
C'est juste une autre façon d'écrire
#define TRUE 1#define FALSE 0
L'expression '/'/'/'divisera la valeur char de '/'elle-même, ce qui donnera 1 comme résultat.
L'expression '-'-'-'va soustraire la valeur char de '-'d'elle-même, ce qui donnera 0 comme résultat.
Les crochets autour des defineexpressions entières manquent cependant, ce qui peut entraîner des erreurs dans le code à l'aide de ces macros. La réponse de Jay répond assez bien à cela.
Un exemple de scénario "réel" où l'oubli des crochets peut être nuisible est l'utilisation combinée de ces macros avec un opérateur de cast de style C. Si quelqu'un décide de convertir ces expressions boolen C ++ par exemple:
int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\
o, world!\n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);}
(Lien vers le programme ici , il y a un indice de ce que fait ce programme dans la page IOCCC ci-dessus.)
Aussi, si je me souviens bien, ces expressions étaient des macros obscurcies TRUEet FALSEétaient également couvertes dans le livre "Obfuscated C and Other Mysteries" de Don Libes (1993).
C'est une façon hilarante d'écrire des macros pour Trueet False.
Comme de nombreuses explications ont été fournies, cela /signifie qu'un nombre de 1 octet (selon ASCII) lorsqu'il est divisé par lui-même, il vous donne 1qui sera traité comme Trueet -est également à nouveau un nombre d'octets lorsqu'il est soustrait de la même valeur qu'il vous donne 0qui sera interprétée commefalse
#define TRUE '/'/'/'#define FALSE '-'-'-'
par conséquent, nous pouvons remplacer /ou -avec n'importe quel caractère que nous aimons, par exemple:
#define TRUE '!'/'!'#define FALSE 'o'-'o'
Gardera la même signification que l'expression originale.
Commençons par vrai. Vous pouvez le lire comme '/' / '/', ce qui signifie "caractère '/' divisé par caractère '/'". Étant donné que chaque caractère, en C, est une valeur numérique (sur un octet), il peut être lu comme "la valeur ASCII du caractère '/' divisé par la valeur ASCII de ce même caractère", ce qui signifie 1 (car, évidemment, x / x est 1). Par conséquent, TRUEest 1.
Pour FALSE, c'est le même raisonnement: '-'-'-'lit '-' - '-', c'est-à-dire "la valeur ASCII de '-' moins la valeur ASCII de '-'", qui est 0. Par conséquent, FALSEest 0.
@Fabien: Cela ne dépend pas de l' ASCII. '/'/'/'est 1 pour tout jeu de caractères valide, que ce soit '/' == 47(comme c'est en ASCII), ou '/' == 97(comme c'est en EBCDIC), ou toute autre valeur.
Keith Thompson
4
@Pawel: Une mise en œuvre conforme C ne peut pas la carte '/'à 0. Cette valeur est réservée au caractère nul.
Keith Thompson
2
Vous êtes pédant.
Matheus208
3
@ Matheus208 Si Pawel était pédant, alors c'est ('-'-'-') puisque son argument était basé sur une condition non déclarée; décrire les remarques de Keith comme pédant pourrait être plus ('/' / '/') mais je les appellerais "clarifiant" (et avec les smileys ajoutés "pédant" me semble définitivement '/' - '/'). Il se peut ('-' / '-') que les commentaires pris ensemble puissent être appelés pédants mais, 1) n'est-ce pas quelque peu obligatoire dans ce domaine? 2) ils m'ont fait réfléchir; et 3) je suis un peu plus clair sur certaines choses que je ne l'étais. Et oui, je suppose que je suis moi-même pédant! (Mais je suis plus clair sur ce que signifie "pédant" que moi! ;-)
Réponses:
Voyons voir:
'/' / '/'
signifie lechar
littéral/
, divisé par lechar
littéral'/'
lui-même. Le résultat est un, ce qui semble raisonnableTRUE
.Et
'-' - '-'
signifie lechar
littéral'-'
, soustrait de lui-même. C'est zéro (FALSE
).Il y a deux problèmes avec cela: d'abord, ce n'est pas lisible. Utilisation
1
et0
est absolument mieux. De plus, comme TartanLlama et KerrekSB l'ont souligné, si vous prévoyez d'utiliser cette définition, veuillez ajouter des parenthèses autour d'eux afin de ne pas avoir de surprise:Cela affichera la valeur du
char
littéral'-'
(45 sur mon système).Avec des parenthèses:
le programme imprime correctement zéro, même si cela n'a pas beaucoup de sens de multiplier une valeur de vérité par un entier, mais ce n'est qu'un exemple du genre de bogues inattendus qui pourraient vous mordre si vous ne mettez pas vos macros entre parenthèses.
la source
if
au lieu de le multiplierTRUE
par un entier.notx = TRUE- x;
et à mesure . Sauf queTRUE-FALSE
c'est -44 (en supposant ASCII)C'est juste une autre façon d'écrire
L'expression
'/'/'/'
divisera la valeur char de'/'
elle-même, ce qui donnera 1 comme résultat.L'expression
'-'-'-'
va soustraire la valeur char de'-'
d'elle-même, ce qui donnera 0 comme résultat.Les crochets autour des
define
expressions entières manquent cependant, ce qui peut entraîner des erreurs dans le code à l'aide de ces macros. La réponse de Jay répond assez bien à cela.Un exemple de scénario "réel" où l'oubli des crochets peut être nuisible est l'utilisation combinée de ces macros avec un opérateur de cast de style C. Si quelqu'un décide de convertir ces expressions
bool
en C ++ par exemple:Voici ce que nous obtenons:
Donc
(bool) TRUE
, évaluerait réellementfalse
et(bool) FALSE
évalueraittrue
.la source
Cela équivaut à écrire
Ce que
'/'/'/'
fait réellement l'expression, c'est diviser le caractère/
(quelle que soit sa valeur numérique) par lui-même, il devient donc1
.De même, l'expression
'-'-'-'
soustrait le caractère-
de lui-même et évalue à0
.Il vaudrait mieux écrire
pour éviter un changement accidentel des valeurs lorsqu'il est utilisé avec d'autres opérateurs de priorité supérieure.
la source
Jay a déjà répondu pourquoi les valeurs de ces expressions sont
0
et1
.Par souci d'histoire, ces expressions
'/'/'/'
et'-'-'-'
proviennent d'une des entrées du 1er Concours International de Code C Obfuscated en 1984 :(Lien vers le programme ici , il y a un indice de ce que fait ce programme dans la page IOCCC ci-dessus.)
Aussi, si je me souviens bien, ces expressions étaient des macros obscurcies
TRUE
etFALSE
étaient également couvertes dans le livre "Obfuscated C and Other Mysteries" de Don Libes (1993).la source
C'est une façon hilarante d'écrire des macros pour
True
etFalse
.Comme de nombreuses explications ont été fournies, cela
/
signifie qu'un nombre de 1 octet (selon ASCII) lorsqu'il est divisé par lui-même, il vous donne1
qui sera traité commeTrue
et-
est également à nouveau un nombre d'octets lorsqu'il est soustrait de la même valeur qu'il vous donne0
qui sera interprétée commefalse
par conséquent, nous pouvons remplacer
/
ou-
avec n'importe quel caractère que nous aimons, par exemple:Gardera la même signification que l'expression originale.
la source
Commençons par vrai. Vous pouvez le lire comme
'/' / '/'
, ce qui signifie "caractère '/' divisé par caractère '/'". Étant donné que chaque caractère, en C, est une valeur numérique (sur un octet), il peut être lu comme "la valeur ASCII du caractère '/' divisé par la valeur ASCII de ce même caractère", ce qui signifie 1 (car, évidemment, x / x est 1). Par conséquent,TRUE
est 1.Pour
FALSE
, c'est le même raisonnement:'-'-'-'
lit'-' - '-'
, c'est-à-dire "la valeur ASCII de '-' moins la valeur ASCII de '-'", qui est 0. Par conséquent,FALSE
est 0.C'est une mauvaise façon de dire l'évidence.
la source
'/'/'/'
est 1 pour tout jeu de caractères valide, que ce soit'/' == 47
(comme c'est en ASCII), ou'/' == 97
(comme c'est en EBCDIC), ou toute autre valeur.'/'
à0
. Cette valeur est réservée au caractère nul.