N-PN White-Hat Project
[C] Local Computation - Version imprimable

+- N-PN White-Hat Project (https://dev.n-pn.fr/forum)
+-- Forum : Programmation (https://dev.n-pn.fr/forum/forumdisplay.php?fid=72)
+--- Forum : Langages compilés (https://dev.n-pn.fr/forum/forumdisplay.php?fid=25)
+--- Sujet : [C] Local Computation (/showthread.php?tid=3725)



[C] Local Computation - octarin - 21-08-2014

J'ai découvert cette fonctionnalité du C permettant de récupérer le résultat d'un algorithme autrement que par une fonction. Cela sert (selon moi) à clarifier le code.

Voici un exemple avec la suite de fibonacci.
Code C :

#include <stdio.h>

int main(void)
{
    int lim = 6;
    int nb;

    nb = ({
            int a, b, i;
            b = 1 + (a = 0);
            while (lim--) {
                b = a + b;
                a = b - a;
            }

            b = b;
            });

    printf("Le %de nombre de la suite de fibonacci est %d\n", lim, nb);

    return 0;
}
 


Edit: Cela semble particulièrement utile dans une macro

Code C :

#include <stdio.h>

#define fibonacci(l) ({
            int a, b, i, lim = l; \
            b = 1 + (a = 0); \
            while (lim--) { \
                b = a + b; \
                a = b - a; \
            } \

            b = b; \
            });

int main(void)
{
    int lim = 6;
    int nb;

    nb = fibonacci(lim);
    printf("Le %de nombre de la suite de fibonacci est %d\n", lim, nb);

    return 0;
}
 


Edit2: Bon, si quelqu'un trouve le moyen de le faire marcher dans une macro...


RE: [C] Local Computation - ark - 22-08-2014

Tiens, je connaissais pas ce truc, intéressant faut voir si c'est vraiment utile par contre, parce que je trouve pas que ça aide a la lisibilité du code, au contraire!


RE: [C] Local Computation - Junky - 22-08-2014

Bonjour,

Moi c'est le 'b = b' que je ne comprends pas trop en faite! :/


RE: [C] Local Computation - notfound - 22-08-2014

(22-08-2014, 10h05)Junky a écrit : Bonjour,

Moi c'est le 'b = b' que je ne comprends pas trop en faite! :/

Imho c'est une erreur de frappe.
Ca doit plutôt être nb=b; sachant qu'il utilise printf("Le %de nombre de la suite de fibonacci est %d\n", lim, nb);


RE: [C] Local Computation - Junky - 22-08-2014

Humm je suis pas sur pour le coup Gros!

Si on regarde son code, le nb est _HORS_ du define. Et de plus le nb == le retour du define. Ou alors je suis passé a côté d'un truc.


RE: [C] Local Computation - ark - 22-08-2014

Moi je note quand même qu'il a dit que ca avait pas l'air de marcher dans le define. Donc peut être que c'est une faute.
Après, c'est peut être effectivement une particularité de la syntaxe.


RE: [C] Local Computation - notfound - 22-08-2014

Bon ok. En fait le code est tout pourri.

(J'ai réussi a compiler et exec + avoir le bon résultat, j'finis mon inter et j'poste ça)
Edit en cours...


RE: [C] Local Computation - Junky - 22-08-2014

Fait nous un diff Smile


RE: [C] Local Computation - notfound - 22-08-2014

Chose promise, chose dûe. Comme dit plus haut (post que j'aurai pu éditer si ce vieux c*n de Junky n'avait pas brisé le thread :p) le code est fucked up de partout, même fibo ne marchait pas...
Bref, voici un code qui compile et qui fonctionne :

Code C :

#include <stdio.h>
#define fibonacci(l)({ \
    int i=0, a=0, b=1, s=0 ; \

    while ((l-- - 1)){ s = a + b; a = b; b = s; i++; } \
    nb = b; \
});
int main(void){
    int lim=9;
    int nb;
    nb = fibonacci(lim);
    printf("fib(%d) = %d\n", lim, nb);                                                                                                                                                                                                                                  

    return 0;
}
 


Exec :
Code BASH :

>>> gcc fib_def.c -o OCT ; ./OCT
fib(0) = 34
 


Juste un petit soucis quand je veux afficher fib(<lim>); ça fout 0. J'vous laisse chercher pourquoi.


RE: [C] Local Computation - ark - 22-08-2014

(22-08-2014, 11h40)notfound a écrit : Juste un petit soucis quand je veux afficher fib(<lim>); ça fout 0. J'vous laisse chercher pourquoi.

Je sais pas si j'ai bien compris, pour moi, tu veux faire : printf("%d\n", fib(lim));

Si c'est ca, ma réponse serait: parce qu'il y a pas de valeur de retour parce que ça n'est pas une fonction, du coup il print le truc qui est dans RAX, ce qui fout potentiellement la merde ouais.
Accessoirement, en l'état, ca ne compile pas, j'ai été obligé de virer le ';' a la fin de la macro pour pouvoir compiler de cette manière.

Alors du coup, je viens de tester de rajouter ça à la fin de la macro :
Code C :

asm ("movl %0, %%eax"::"r"(nb);
 


Mais lors de la compilation, gcc affiche un message d'erreur comme quoi il ne doit PAS y avoir de valeur de retour.

Ensuite, pour modifier eax un peu indirectement, je me suis dit que je pouvais call une fonction pour faire en sorte qu'elle return la bonne valeur, et comme RAX ne serait pas modifié entre temps, on pourrait le return.
Sauf que la aussi, meme message d'erreur a la compilation.

Pour le coup, ce code fonctionne :
Code C :

#include <stdio.h>

int test(int nb) {
  return nb;
}

#define fibonacci(l)({ \
      int i=0, a=0, b=1, s=0 ;                  \
      while ((l-- - 1)){ s = a + b; a = b; b = s; i++; }    \
      test(b);                          \
    });


int main(void){
  int lim=9;
  int nb;
 
  nb = fibonacci(lim);
  printf("fib(%d) = %d\n", lim, nb);
  return 0;
}
 


En revanche, celui ci ne compiles pas:
Code C :


#include <stdio.h>
#define fibonacci(l)({ \
      int i=0, a=0, b=1, s=0 ;                  \
      while ((l-- - 1)){ s = a + b; a = b; b = s; i++; }    \
      asm ("movl %0, %%eax"::"r"(nb);

    });

int main(void){
  int lim=9;
  int nb;
 
  nb = fibonacci(lim);
  printf("fib(%d) = %d\n", lim, nb);
  return 0;
}
 



RE: [C] Local Computation - eax64 - 29-08-2014

Plop,
dans la macro, en remplacent
Code C :

nb = b;
 


par
Code C :

b;
 

ça marche et c'est moins moche.

Ce qui donne:

Code C :

#include <stdio.h>
#define fibonacci(l)({ \
    int i=0, a=0, b=1, s=0 ; \
    while ((l-- - 1)){ s = a + b; a = b; b = s; i++; } \
    b; \
})


int main(void){
    int lim=9;
    printf("fib(%d) = %d\n", lim, fibonacci(lim));
    return 0;
}
 
 



RE: [C] Local Computation - b0fh - 29-08-2014

Je crois qu'on n'a pas les mêmes critères de lisibilité Smile Ce type de gadget peut dysfonctionner de manière subtile et non-intuitive (je me demande combien ici ont vraiment testé ce code...) par exemple:

Code C :
for(lim = 1; lim < 10; ++lim) {
      printf(fibonacci(lim));
   }


ne marchera pas, parce que lim est modifié pendant le contenu de l'appel a fibonacci, un comportement contre-intuitif car impossible avec une fonction classique.

En supposant qu'on corrige la macro pour éviter ça, en faisant une copie de l avant exécution,

Code :
int lim = 1;
while(lim < 10) {
    printf("...", fibonacci(lim++))
}

serait également sémantiquement équivalent à la première boucle si fibonacci était une fonction classique, mais peut donner un truc différent suivant l'implémentation de la macro, si l'argument est évalué plusieurs fois.

De manière générale, les macros en C sont dangereuses et contre-intuitives, sauf si on respecte les contraintes suivantes, plutôt contraignantes:

- parenthèses autour de l'expression top-level
- parenthèses autour de tous les arguments
- évaluation de chaque argument une et une seule fois (et donc pas de boucles avec un argument dans le corps, ou de branches if/else avec un nombre d'appels différents aux arguments dans chaque branche)

Il y a des limitations supplémentaires: comportement bizarre en cas de shadowing, ou d'aliasing de plusieurs arguments, impossibilité de prendre un pointeur vers la fonction...

Les macros sont une relique d'une décennie antérieure. Il n'y en a pas dans les langages modernes. Même C++ s'en était déja largement débarassé au profit d'une alternative type-safe, les templates. Les compilos modernes savent inliner les fonctions courtes.

Conclusion: chaque fois que vous utilisez une macro la ou une alternative existe, Dieu tue un chaton ! alors soyez gentils avec les chatons.