IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Bizarreries du langage C


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    55
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 55
    Par défaut Bizarreries du langage C
    Bonjour à tous et à toutes,

    Je m'étais dit que ca pourrait être intéressant de regrouper quelque part, l'ensemble des 'bizareries' du langage C.

    Qu'est ce que j'entends par 'bizareries'?
    Ce n'est pas le meilleur terme je le concoit, mais je n'en ai pas trouvé d'autre.
    Il s'agirait plutôt de code difficile à interpréter, de choses qui ne semblent pas compiler, etc.

    Comme un exemple vaut mieux qu'un long discours, voici des exemples:
    -Le fait d'inverser l'index avec la variable du tableau : tab[1] équivaut à 1[tab]
    -De déclarer des variables dans un switch mais ailleurs que dans un case, puis de l'afficher.

    Donc si vous avez des idées ou bouts de code qui traine, c'est le moment!

    Bonne soirée!

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Salut

    Ton idée n'est pas nouvelle. Il existe même un concours du programme C le plus illisible. Je crois qu'en tapant des mots clefs comme "worst" "programming" dans google tu peux trouver ça

    Toutefois, c'est pas évident de qualifier ce qui est bizarre. Déjà pourquoi est-ce bizarre ? Parce que c'est peu usité (comme ton exemple tab[i] <=> i[tab] et, pour faire suivre, tab[i][j] <=> j[i[tab]]) ? C'est vrai que le terme est un peu inadéquat. Après-tout, si la syntaxe est acceptée alors elle n'a rien de bizarre.

    Mais bon, je vais contribuer à ton effort. Regarde ce code
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #include <stdio.h>
    int carre(int x)
    {
         return x * x;
    }
     
    int main()
    {
        void *ptF=carre;
     
        printf("Le carré de 2 est %d\n", (*ptF)(2));
        printf("Le carré de 3 est %d\n", (**ptF)(3));
        printf("Le carré de 4 est %d\n", (***ptF)(4));
        printf("Le carré de 5 est %d\n", (****ptF)(5));
    }

    Et tu peux rajouter autant d'étoiles que ça te chante. Ca c'est une sacré bizarrerie non ???
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre Expert Avatar de jabbounet
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juin 2009
    Messages
    1 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 909
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Salut

    Ton idée n'est pas nouvelle. Il existe même un concours du programme C le plus illisible. Je crois qu'en tapant des mots clefs comme "worst" "programming" dans google tu peux trouver ça
    tu veux parler de
    http://www.ioccc.org/main.html

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 485
    Par défaut
    Citation Envoyé par jabbounet Voir le message
    J'adore particulièrement, comme tout le monde, je crois, le programme du vainqueur du calcul de Pi en 1988 !

    Sinon, cette citation, également :

    15:15 j'ai la chaine de char "./foo" c quoi en C le plus simple pour
    juste avoir "foo" ?
    15:16 15:15 foo+2
    15:21 15:16 ou alors &2[foo] , c'est rigolo aussi
    15:24 15:21 et plus on &2[foo], plus on rit...

    On peut citer aussi le swap de variables

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    x ^= y;
    y ^= x;
    x ^= y;

    … qui se « simplifie » en :

    … (vu ici), ainsi que les cute codes tels que :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    c = "0123456789abcdef"[n];

    …pour faire les conversions hexadécimales. :-)

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    55
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 55
    Par défaut
    Ton idée n'est pas nouvelle. Il existe même un concours du programme C le plus illisible.
    Comme dit précédemment ce n'est pas forcément une question de lisibilité, juste de comportement jamais testé, et autres autorisations de la syntaxe C.

    Je crois qu'en tapant des mots clefs comme "worst" "programming" dans google tu peux trouver ça
    Merci, je jetterais un oeil, car mes recherches francaise n'avaient pas donné grand chose!

    Après-tout, si la syntaxe est acceptée alors elle n'a rien de bizarre.
    Nous sommes d'accord, après ce n'est qu'une question de connaissance. Tout comme l'ajout d'instructions dans le switch.

    En revanche le code que tu as donné ne compile pas chez moi...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    moi::localhost> alias gcc
    gcc='gcc -W -Wall -ansi -pedantic'
    moi::localhost> gcc fptr2.c
    fptr2.c: In function ‘main’:
    fptr2.c:9: warning: ISO C forbids initialization between function pointer andvoid *’
    fptr2.c:11: warning: dereferencing ‘void *’ pointer
    fptr2.c:11: error: called object ‘*ptF’ is not a function
    fptr2.c:12: warning: dereferencing ‘void *’ pointer
    fptr2.c:12: error: void value not ignored as it ought to be
    fptr2.c:13: warning: dereferencing ‘void *’ pointer
    fptr2.c:13: error: void value not ignored as it ought to be
    fptr2.c:14: warning: dereferencing ‘void *’ pointer
    fptr2.c:14: error: void value not ignored as it ought to be
    moi::localhost>
    En revanche celui-ci donne le comportement attendu:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    #include <stdio.h>
     
    int	carre(int x)
    {
         return x * x;
    }
     
    int	main()
    {
      int (*ptF)(int) = &carre;
     
      printf("Le carrM-CM-) de 2 est %d\n", (*ptF)(2));
      printf("Le carrM-CM-) de 3 est %d\n", (**ptF)(3));
      printf("Le carrM-CM-) de 4 est %d\n", (***ptF)(4));
      printf("Le carrM-CM-) de 5 est %d\n", (****ptF)(5));
      return (0);
    }
    Et en effet, c'est bizzare!
    Merci de la contribution!

  6. #6
    Membre éprouvé
    Inscrit en
    Juin 2008
    Messages
    91
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 91
    Par défaut
    Citation Envoyé par ugo188 Voir le message
    En revanche le code que tu as donné ne compile pas chez moi...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    moi::localhost> alias gcc
    gcc='gcc -W -Wall -ansi -pedantic'
    moi::localhost> gcc fptr2.c
    fptr2.c: In function ‘main’:
    fptr2.c:9: warning: ISO C forbids initialization between function pointer andvoid *’
    fptr2.c:11: warning: dereferencing ‘void *’ pointer
    fptr2.c:11: error: called object ‘*ptF’ is not a function
    fptr2.c:12: warning: dereferencing ‘void *’ pointer
    fptr2.c:12: error: void value not ignored as it ought to be
    fptr2.c:13: warning: dereferencing ‘void *’ pointer
    fptr2.c:13: error: void value not ignored as it ought to be
    fptr2.c:14: warning: dereferencing ‘void *’ pointer
    fptr2.c:14: error: void value not ignored as it ought to be
    moi::localhost>
    Bonjour,

    Effectivement, le C standard ne définit pas de comportement issu d'une conversion d'un pointeur sur fonction à un pointeur générique. Le bon fonctionnement d'une telle pratique est soumis à la disponibilité d'une extension de compilateur. Cette extension a été inhibée par le flag -pedantic.



    Pour ma part :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    typedef int (*(*foo)(void *(*)(void*foo),int(*(*foo)(void*foo))[5]))[10];
    int main(void)
    {
        foo f;
        return 0;
    }
    Celui qui parvient à initialiser l'objet 'f' et l'utiliser convenablement recevra une médaille de ma part .

    Une autre bizarrerie :
    f1.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include <stdio.h>
    extern char * foo;
     
    void f1(void)
    {
          puts(foo);
    }
    f2.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include <stdio.h>
    extern char foo[50];
     
    void f2(void)
    {
          puts(foo);
    }
    main.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    char foo[50] = "Hello world";
    extern void f1(void);
    extern void f2(void);
     
    int main(void)
    {
          f1();
          f2();
          return 0;
    }
    N'hésitez pas à expliquer le bogue généré par ce petit programme si vous avez une explication. Une médaille est prévue pour le gagnant .

    Et pour la route :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /*Ceci ne devrait pas choquer*/
    int main(void)
    {
           void foo(int [20]);
           int t1[50];
           int t2[6];
           int t3[20];
     
           foo(t1);
           foo(t2);
           foo(t3);
     
           return 0;
    }
     
    void foo(int t[20])
    {
           t[0] = 0;
    }

  7. #7
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par uknow Voir le message
    Effectivement, le C standard ne définit pas de comportement issu d'une conversion d'un pointeur sur fonction à un pointeur générique. Le bon fonctionnement d'une telle pratique est soumis à la disponibilité d'une extension de compilateur. Cette extension a été inhibée par le flag -pedantic.
    Et occasionnellement, on ne peut pas déréférencer un void*.


    Citation Envoyé par uknow Voir le message
    Une autre bizarrerie :
    f1.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include <stdio.h>
    extern char * foo;
     
    void f1(void)
    {
          puts(foo);
    }
    f2.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include <stdio.h>
    extern char foo[50];
     
    void f2(void)
    {
          puts(foo);
    }
    main.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    char foo[50] = "Hello world";
    extern void f1(void);
    extern void f2(void);
     
    int main(void)
    {
          f1();
          f2();
          return 0;
    }
    N'hésitez pas à expliquer le bogue généré par ce petit programme si vous avez une explication. Une médaille est prévue pour le gagnant .
    Déclaration d'un extern avec un type différent de la définition.
    Au passage, dans f2.c (et dans f1.c si on souhaite corriger le problème), extern char foo[]; suffit et est globalement plus simple à maintenir (en supposant que la globale soit justifiée bien sur).


    Dans les classiques, qui n'est pas compliqué à comprendre mais qui surprend quand on tombe dessus la première fois (heureusement gcc correctement réglé les signale), il y a l'utilisation des trigraphes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ??=include <stdio.h>
     
    int main()
    ??<
    	char tab??(??) = "abc";
     
    	if(tab??(0??) == 'd' ??!??!tab??(0??) == 'a')
    	??<
    		printf("Hello!");
    	??>
     
    	return 0;
    ??>

  8. #8
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    typedef int (*(*foo)(void *(*)(void*foo),int(*(*foo)(void*foo))[5]))[10];
    C'est plutôt un exercice pour décoder les déclarations complexes en C :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     int (*(*foo)(void *(*)(void*foo),int(*(*foo)(void*foo))[5]))[10]
    (*(*foo)(void *(*)(void*foo),int(*(*foo)(void*foo))[5]))  // est tableau de 10 int
    *(*foo)(void *(*)(void*foo),int(*(*foo)(void*foo))[5])  // est tableau de 10 int
    (*foo)(void *(*)(void*foo),int(*(*foo)(void*foo))[5])  // est pointeur sur tableau de 10 int
    (*foo)  //est fonction retournant un pointeur sur tableau de 10 int
    // foo est pointeur sur fonction retournant un pointeur sur tableau de 10 int
    Liste des arguments de cette fonction : void *(*)(void*foo),int(*(*foo)(void*foo))[5] . Tous ces foo ne sont que les noms optionels des paramètres.
    Premier argument :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void *(*)(void*foo)
    (*)(void*foo) // est pointeur sur void
    (*) // est fonction retournant un pointeur sur void
    // est pointeur sur fonction retournant un pointeur sur void, ayant pour argument un pointeur sur void
    Deuxième argument :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int(*(*foo)(void*foo))[5]
    (*(*foo)(void*foo)) //  est tableau de 5 int
    *(*foo)(void*foo) // est tableau de 5 int
    (*foo)(void*foo) // est pointeur sur tableau de 5 int
    (*foo) // est fonction retournant un pointeur sur tableau de 5 int
    // est pointeur sur fonction retournant un pointeur sur tableau de 5 int, ayant pour argument un pointeur sur void
    Au final :
    foo est un pointeur sur une fonction retournant un pointeur sur un tableau de 10 int dont le premier argument est un pointeur sur une fonction retournant un pointeur sur void et ayant pour argument un pointeur sur void, et le second argument est un pointeur sur fonction retournant un pointeur sur un tableau de 5 int et ayant pour argument un pointeur sur void

    C'est équivalent à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    typedef int T10[10];
    typedef int T5[5];
    typedef void * TFoncA(void*);
    typedef T5 * TFoncB(void*);
    typedef T10 *(* foo)(TFoncA f1, TFoncB f2) ;
    Application :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    //---------------------------------------------------------------------------
    typedef int T10[10];
    typedef int T5[5];
    typedef void * TFoncA(void*);
    typedef T5 * TFoncB(void*);
    typedef int (*(*foo)(void *(*)(void*foo),int(*(*foo)(void*foo))[5]))[10];
    typedef T10 *(* foo)(TFoncA f1, TFoncB f2) ; // équivalent à la définition précédente
    //---------------------------------------------------------------------------
    void * foncA(void* a)
    {
      return a;
    }
    //---------------------------------------------------------------------------
    T5 * foncB(void* b)
    {
      return b;
    }
    //---------------------------------------------------------------------------
    T10 * fonc(TFoncA f1, TFoncB f2)
    {
      return NULL;
    }
    //---------------------------------------------------------------------------
    int main(void)
    {
        T10 * p;
        foo f = fonc;
        p = f(foncA, foncB);
        return 0;
    }
    //---------------------------------------------------------------------------
    Ai-je mérité une médaille ?

  9. #9
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par jabbounet Voir le message
    Ouais c'est ça. C'est le concours des grands malades

    Citation Envoyé par ugo188 Voir le message
    En revanche le code que tu as donné ne compile pas chez moi...
    Oui, désolé, j'ai posté ce code de mémoire suite à un truc que j'avais remarqué il y a fort longtemps ; et commis l'erreur de ne pas le tester. Merci de l'avoir rectifié au niveau de la déclaration de ptF.

    Citation Envoyé par uknow Voir le message
    Une autre bizarrerie :
    f1.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include <stdio.h>
    extern char * foo;
     
    void f1(void)
    {
          puts(foo);
    }
    f2.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include <stdio.h>
    extern char foo[50];
     
    void f2(void)
    {
          puts(foo);
    }
    main.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    char foo[50] = "Hello world";
    extern void f1(void);
    extern void f2(void);
     
    int main(void)
    {
          f1();
          f2();
          return 0;
    }
    N'hésitez pas à expliquer le bogue généré par ce petit programme si vous avez une explication. Une médaille est prévue pour le gagnant
    En fait, f2 est inutile car f1 suffit pour générer le bogue. C'est parce que, même si on peut les utiliser de façon similaire dans 98% des cas, un pointeur n'est pas un tableau. Et ton exemple fait partie des 2% qui le prouvent...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. [langage] Je cherche un bon livre ?
    Par Anonymous dans le forum Langage
    Réponses: 13
    Dernier message: 09/04/2003, 13h16
  2. [langage] Comparer Perl avec d'autres langages comme C ?
    Par Anonymous dans le forum Langage
    Réponses: 3
    Dernier message: 10/08/2002, 23h52
  3. [langage] comment créer des fichiers ?
    Par Anonymous dans le forum Langage
    Réponses: 3
    Dernier message: 05/05/2002, 16h33
  4. Comparer des fichiers de données : Quel Langage ?
    Par Anonymous dans le forum Langages de programmation
    Réponses: 6
    Dernier message: 24/04/2002, 22h37
  5. Cours, tutoriels, logiciels, F.A.Q,... pour le langage SQL
    Par Marc Lussac dans le forum Langage SQL
    Réponses: 0
    Dernier message: 04/04/2002, 10h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo