2011-02-27 4 views
0

J'implémente un simulateur d'ordinateur en C avec le défi de ne pas utiliser les conditions (ie pas/sinon, commutateur/cas, alors que/pour, etc.). Il y a beaucoup de mux dans le matériel que je simule, donc ce serait bien si je pouvais utiliser les opérateurs de logique ternaire conditionnelle. Donc, ma question: les compilateurs C créent-ils une logique MUX à partir d'opérateurs logiques ternaires, ou créent-ils des branches?Connexion entre la logique ternaire et la logique multiplex?

Exemple:

int a, b, q, r; 
/* Ternary logic */ 
r = q ? a : b; 
/* MUX equivalent logic */ 
r = (q & a) | ((~q) & b) 
/* Branch equivalent logic */ 
if (q) r = a; else r = b; 

Répondre

4

L'opérateur ternaire est équivalent à une branche:-à-dire la valeur renvoyée est non pas évaluée.

Je ne sais pas combien vous êtes contraint, donc notez que les opérateurs booléens && et || n'évaluent pas leur deuxième argument est le résultat peut être déterminé à partir de la première.

(Et notez que la ligne "MUX" n'est pas très différente des deux autres expressions: elle sélectionne les bits de a ou b en fonction de la valeur du bit correspondant dans q, elle ne sélectionne pas a ou b selon que q est nul ou pas, Edit: c'est pire: vous utilisez! q et non ~ q ...).

+0

1. Je comprends qu'un opérateur ternaire est équivalent à une branche, comme je l'ai indiqué ci-dessus. Ce que je demande est, "le compilateur génère-t-il une branche au niveau de l'assemblage?" 2. Je n'ai trouvé aucune utilité pour && et || opérateurs booléens jusqu'à présent. Je vais garder votre idée en tête. 3. Je suis confus par votre utilisation du terme "nul". Mais vous avez raison, je devrais passer à ~ pour la plupart des cas (cela devait être un simple exemple de valeur de 1 bit, mais je vais le modifier). – Robz

+0

@Robz: 1. en général, oui. –

+0

1. Oui (il ne doit pas évaluer l'autre branche). 3. zéro – AProgrammer

1

Les compilateurs C créent des branches à partir d'instructions ternaires.

En utilisant CodeWarrior de Freescale, je compilé le programme C:

int a, b, q, r;  
void main(void) {  
    a = 0;  
    b = 1;  
    q = 0;  
    r = q ? a : b;  
.. 
..  
} 

L'ensemble correspondant à la déclaration ternaire est la suivante:

... 
LDX 0x1104 ; load val[q] into register x  
BNE *+4 ; branch to abs addr 0xC016 if val[q]==a  
BRA *+5 ; branch to abs addr 0xC019 if val[q]!=a 
... 
1

Souvent, la logique de branchement est créé, mais Il est très possible de faire des opérations ternaires sans aucun type de branche si les deux valeurs sont évaluées. Considérez ceci:

#include <stdio.h> 

static inline int isel(int cond, int a, int b) 
{ 
    int mask = cond | (-cond); 
    mask >>= 31; 
    return (b & mask) | (a & ~mask); 
} 

int main(void) 
{ 
    printf("1 ? 3 : 4 => %d\n", isel(1, 3, 4)); 
    printf("0 ? 3 : 4 => %d\n", isel(0, 3, 4)); 
    printf("-1 ? 3 : 4 => %d\n", isel(-1, 3, 4)); 
    return 0; 
} 

Ce code suppose que droit déplacement des nombres signés signera-s'étendre, et que sizeof (int) == 4. Certains processeurs peuvent faire ISEL() comme une instruction de montage. Cependant, les deux valeurs seront évaluées, ce que le ternaire?: Ne fait pas. En fonction de la situation, le compilateur essaiera généralement de faire le plus rapidement possible, soit en se ramifiant pour éviter le calcul redondant, soit en faisant ce genre de logique si les valeurs dans l'expression ternaire sont simples.

+0

Cool! J'ai utilisé une structure avec des champs de bits pour signer étendre les signaux de bits, mais cela fonctionne aussi, merci! Au départ, je pensais que le compilateur aurait tendance à éviter les succursales à tout prix, mais comme vous le dites, il est également logique de vérifier le «calcul redondant». – Robz