• # 100% collègue

    Posté par  (site web personnel) . Évalué à 10.

    Le premier effet de ce code sera de faire écrire un commentaire ou un ticket par un collègue pour demander ce que tu as voulu faire et si tu peux le réécrire de façon lisible.

    Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

    • [^] # Re: 100% collègue

      Posté par  (site web personnel, Mastodon) . Évalué à 4.

      J’allais écrire « un commentaire dans la MR pour réécrire ce code (ou au moins mettre l’explication en commentaire si le code est légitime) », et donc je te rejoins.

      La connaissance libre : https://zestedesavoir.com

  • # Non

    Posté par  . Évalué à 6.

    …du moins pas avant mon quatorzième café!

    Ça fait 35 ans que je n'ai plus fait de C. Je ne sais pas si cette ligne était valide à cette époque-là, mais dans l'affirmative, elle était déjà aussi illisible.

  • # Je tente

    Posté par  (site web personnel) . Évalué à 10.

    a est un entier de valeur indéterminée.
    b est un pointeur constant vers un entier, l'adresse pointée est, heu…, indéterminée mais fixe ?
    c est, heu…, un tableau de 10 pointeurs non initialisés de fonctions sans paramètres qui retournent un pointeur vers un entier.
    d est un tableau de deux pointeurs sur entiers, le premier est l'adresse de a et le second est null.

    J'ai bon ? C'est pas facile de tête sur téléphone en vacances :)

    • [^] # Re: Je tente

      Posté par  . Évalué à 3.

      c est, heu…, un tableau de 10 pointeurs non initialisés de fonctions sans paramètres qui retournent un pointeur vers un entier.

      Je dirais plutôt une fonction sans paramètres qui retourne un pointeur vers un tableau de 10 entiers.

      • [^] # Re: Je tente

        Posté par  . Évalué à 4.

        je dirais même un pointeur vers une fonction qui retourne un pointeur vers un tableau de 10 entiers ;-)

    • [^] # Re: Je tente

      Posté par  (site web personnel) . Évalué à 4.

      Petite astuce, cdecl

      declare c as function (void) returning pointer to array 10 of int

      git is great because linus did it, mercurial is better because he didn't

  • # sans tricher

    Posté par  . Évalué à 10. Dernière modification le 11 août 2023 à 10:35.

    Bon sans tricher (j'ai pas demandé à chatToutPété ni à internet, et je n'ai pas lu les autres réponses avant de taper celle-ci)

    • int a : bon ok. Je ne pense pas que ce soit un piege.

    • *const b : pointeur a constant nommé b.

    • (*(c(void)))[10] : tableau de 10 pointeurs de fonction 'c' sans paramètre, retournants un entier.

    • *d[2] = {&a} : tableau d (2 éléments) de pointeurs int initialisés avec l'adresse a qui est indéfinie à ce stade.

    Et maintenant, laissez moi vous dire:
    LES GENS COMME VOUS, ON DEVRAIT FAIRE DES EXPÉRIENCES DESSUS !

    Discussions en français sur la création de jeux videos : IRC freenode / #gamedev-fr

    • [^] # Re: sans tricher

      Posté par  . Évalué à 4. Dernière modification le 11 août 2023 à 10:58.

      juste 2 remarques

      (*(c(void)))[10] : tableau de 10 pointeurs de fonction 'c' sans paramètre, retournants un entier.

      Si je ne dit pas de bêtises, en C, les paramètres des fonctions n'ont pas besoin d'être déclarés dans les pointeurs sur les fonctions.
      D'ailleurs, à l'inverse du C++, les paramètres de fonctions ne sont pas manglés avec le nom de la fonction dans la table des symboles (c'est ce qui permet la surcharge de fonctions en C++ et pas en C)

      *d[2] = {&a} : tableau d (2 éléments) de pointeurs int initialisés avec l'adresse a qui est indéfinie à ce stade.

      elle est indéfinie mais représente la première variable locale si on est dans le corps d'une fonction. Du coup indirectement on peut modifier la valeur du pointeur "b" qui est déclaré constant par exemple comme cela :

      *(d[0] + 1) = &a

      et hop, b pointe maintenant sur a lui aussi ;)
      à priori ça marche aussi si on est pas dans une fonction, c'est juste pas une adresse de la pile mais dans la zone des variables globales du binaire. (.bss s'il me reste des souvenirs en état, mais là vraiment faut aller vérifier, c'est plus de mon âge ces conneries)
      Et dans ce dernier cas, le linker devrait pouvoir la déterminer et la fixer sans avoir besoin de code dynamique si on compile un exécutable et pas une librairie.

      • [^] # Re: sans tricher

        Posté par  . Évalué à 3.

        Si je ne dit pas de bêtises, en C, les paramètres des fonctions n'ont pas besoin d'être déclarés dans les pointeurs sur les fonctions.

        C'est en effet possible avec une liste de paramètres vides '()' mais ici le '(void)' implique une fonction sans aucuns paramètres.

        *d[2] = {&a} : tableau d (2 éléments) de pointeurs int initialisés avec l'adresse a qui est indéfinie à ce stade.

        Le premier élément de d est effectivement initialisé avec l'adresse de a mais le second est initialisé à 0.

        elle est indéfinie mais représente la première variable locale si on est dans le corps d'une fonction. Du coup indirectement on peut modifier la valeur du pointeur "b" qui est déclaré constant par exemple comme cela

        En fait, non. Le compilateur n'a aucune obligation de conserver l'ordre des variables locales ou globales. Pour les variables locales (ou static), il n'est même pas obligé de leur affecter une adresse sauf si cette adresse est utilisée dans le code (par exemple avec &b). En pratique, la variable b peut très bien exister dans un registre ou ne pas exister du tout. Pour les variables globales, la situation est encore plus complexe car les elles sont typiquement rangées dans des zone mémoires différentes en fonction de leur nature (read-only, read-write, initialisé avec des 0, …). Le compilateur peut aussi décider de réordonner les variables pour diverses raisons (alignements, tailles, optimisations, …)

        • [^] # Re: sans tricher

          Posté par  (site web personnel) . Évalué à 3.

          Le compilateur n'a aucune obligation de conserver l'ordre des variables locales ou globales.

          J'allais le dire ! La direction de la pile n'est pas spécifiée dans le standard si je me souviens bien. En plus des arguments que tu as listé.

          Mais ce int* const b non initialisé m'embête. Je suis surpris que ça compile.

        • [^] # Re: sans tricher

          Posté par  . Évalué à 3.

          En effet j'ai allègrement zappé la phase d'optimistion du compilateur et du linker ;)

          Ça doit être parce que je debug… sur des builds compilés en debug et qu'il m'est arrivé de voir de genre de dépassement et de constater l'écrasement des variables adjacentes ;)

  • # Les femmes aiment compiler le C

    Posté par  (Mastodon) . Évalué à 10.

    Et si par hasard il y en a qui ne connaissent pas les concours d'obscurcissement de C, voici le lien indispensable !

    En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

    • [^] # Re: Les femmes aiment compiler le C

      Posté par  . Évalué à 3.

      Il n'y a pas eu d'édition depuis 2020 ?

    • [^] # Re: Les femmes aiment compiler le C

      Posté par  . Évalué à 2. Dernière modification le 12 août 2023 à 22:06.

      IL y a vraiment des trucs incroyable. Il faut que cela tienne sur un nombre limité de caractères (Pas nombreux), et une des astuces, c'est qu’énormément de valeurs sont passées dans le ligne de compilation. Alors évidemment ils l'écrivent en C normal et obscurcissent pour l'épreuve. Mais il y a souvent en plus énormément d'astuce pour limiter le nombre d'instruction.

      Je me souvient

      • d'un simulateur de vol présenté sous la forme d'un avion en ASCII Art. (Il se joue sur console en ascii art)

      • Un tableur excel très complet. Qui s'utilise en console.

      Bref je trouve se concours inutile mais très passionnant.

  • # gépéto

    Posté par  . Évalué à 2.

    Cette ligne de code déclare plusieurs variables en C :

    1. int a : déclare une variable a de type entier.
    2. * const b : déclare un pointeur constant b qui pointe vers une valeur de type indéterminé.
    3. (*(c(void)))[10] : déclare un tableau de pointeurs de taille 10, où chaque élément est un pointeur vers une fonction c qui ne prend pas d'arguments et renvoie un pointeur.
    4. *d[2] = {&a} : déclare un tableau de pointeurs d de taille 2, où chaque élément est un pointeur vers un entier. Le premier élément du tableau d est initialisé avec l'adresse de la variable a.

    En résumé, la ligne de code déclare une variable entière a, un pointeur constant b, un tableau de pointeurs de fonctions c, et un tableau de pointeurs d'entiers d initialisé avec l'adresse de a.

  • # La syntaxe au sens équivalente n'est pas

    Posté par  . Évalué à 4.

    Syntaxiquement, ça compile (peut-être, j'ai pas testé…).

    Et comme avec tout langage (du C, du Python, du rust, du français), on peut balancer des mots qui n'ont ni queue ni tête et chercher le sens à tout ça…

    Pour moi, un tel code ne mérite pas de vivre car il n'exprime aucun sens (d'autant que j'entrevois quelques bouts de "UB" qui vont être compilo-dépendant).

  • # Éléments de réponses

    Posté par  (site web personnel) . Évalué à 7.

    Il n'y a pas d'undefined behavior dans l'exemple si la déclaration a été faite au niveau globale.

    La déclaration suivante :

    int (*(c(void)))[10]

    se lit de l'intérieur vers l'extérieur, en spirale en commençant par le nom de la variable et en commençant à tourner par la droite (tout en mettant un doigt sur le nez et en prononçant très vite l'incantation kerniganetrichie).

    La déclaration suivante est valide :

    int (*(c(void)))[10] { return 0; }
  • # voire aussi

    Posté par  (site web personnel) . Évalué à 2. Dernière modification le 15 août 2023 à 14:47.

  • # Facile

    Posté par  (site web personnel) . Évalué à 9.

    Vu qu'on a pas le reste du code, j'ai le droit de supposer que les variables sont inutilisés, donc d'optimiser ça en retirant le code mort, donc ça crée un binaire qui fait rien.

    Je viens de vérifier codant un main avec cette ligne et un main avec rien. Quand je compile avec -s, il y a 4 lignes en plus:

    movq   $0x0,-0x20(%rbp)
    movq   $0x0,-0x18(%rbp)
    lea    -0x4(%rbp),%rax
    mov    %rax,-0x20(%rbp)
    

    Sauf erreur de ma part, ça initialise 2 variable à 0, et copie une variable de la stack vers ailleurs (un ailleurs mis à 0 plus tot).

    Avec gcc -O3, ça donne bien la même chose entre les 2 codes (cad, rien), ergo, mon analyse est correct.

    • [^] # Re: Facile

      Posté par  (site web personnel) . Évalué à 3.

      Bien tenté ;-)

      En l'absence d'indication, on peut aussi imaginer que les déclarations soient globales, ce qui rend l'ensemble nettement plus intéressant (à défaut d'être complètement utile) et produit le code suivant, même en -O3 (et à juste titre) (cf. https://godbolt.org/z/cYP6j1bsh)

      d:
              .quad   a
              .zero   8
      b:
              .zero   8
      a:
              .zero   4

      Finalement, la seule vraie difficulté du quizz est effectivement jetée aux oubliettes, bien joué !

  • # Bon

    Posté par  . Évalué à 2.

    Je commencerais par dire :

    • ça déclare et définit un entier a
    • ça déclare et définit un pointeur b vers un entier constant. Mais c'est peut être un pointeur constant b vers un entier, personne ne peut savoir ça.
    • je vais prendre un café, mais ça déclare et définit encore deux trucs appelés a et b, dont un des deux est surement un pointeur de fonction qui retourne un pointeur vers un entier, ou pas.

    En tout cas je supprime cette ligne, et je regarde si ça compile encore, auquel cas c'est bien, sinon tant pis, je change des trucs au hasard jusqu'à ce que ça compile, et donc une fois que c'est compilé, c'est que c'est correct.

    Tous les nombres premiers sont impairs, sauf un. Tous les nombres premiers sont impairs, sauf deux.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.