Forum Programmation.c [Résolu] Caractères composés

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
0
28
mar.
2013

Bonjour, bonsoir,

J'ai un petit soucis avec les caractères composés. Je vous poste mon code :

#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>

int ch = 96;

int main(int argc, char **argv)
{
      initscr();
      raw();
      noecho();
      keypad(stdscr, TRUE);
      while(ch != KEY_F(1))
      {
            ch = getch();
            clear();
            printw("char=%c", ch);
            refresh();
      }
      endwin();
      return 0;
}

Quand je lance le programme, si je tape sur 'é', ça m'affiche un '?' dans un losange.
Normal me diriez-vous, le 'é' n'est pas un unique caractère.
Si à la place de '%c', je met '%lc', le programme m'affiche un blanc.
Si je met '%s', il y a une erreur de segmentation, logique…
Ca fait plusieurs jours que j'essaie de me renseigner, et j'ai trouvé plein de chose, notamment les wint_t (wchar_t) que je récupère avec 'getwchar()'. Le souci, c'est que j'arrive absolument pas à les afficher avec le printw de ncurses.
Si mon 'ch' est un 'wint_t', quand je tape 'printw("char=%c", ch); le code fonctionne et plante des que je tape 'é'. (même si je met '%lc')
Enfin bref, ça fait maintenant deux jours que je cherche, et je sature.

Est-ce que quelqu'un connait le moyen de pouvoir afficher un caractère composé récupéré dans l'entrée standard avec printw ?

Merci d'avance pour les réponses !

mistiru

  • # .

    Posté par  . Évalué à 5. Dernière modification le 28 mars 2013 à 23:38.

    Bonjour,

    1) A priori rien a voir avec UTF-8, et crois moi c'est mieux pour toi. ;) Je te conseille quand meme de lire cet excellent article a ce sujet : http://www.joelonsoftware.com/articles/Unicode.html
    Après, tu peux le faire en UTF si tu veux, mais faut comprendre et assumer. Ce serait une façon plus élégante, certes.

    2) Lecture indispensable : man ascii, ca explique bien comment sont gérés les characteres en C (attention, le type char, pas wchar_t)

    3) pourquoi est-ce que tu déclare un int et pas un char ? Certes le retour de getch est un int, mais toi tu cherche a afficher un char, en mémoire ce n'est pas pareil… (en fait je suis meme surpris que ca marche)
    Je soupçonne ton erreur d'être là.

    Après j'ai pas d'environnement pour tester, donc j'espère que ces pointeurs te permettront d'avancer…

    • [^] # Re: .

      Posté par  . Évalué à 1.

      Si je remplace int par char, cela me donne exactement le même résultat.

    • [^] # Re: .

      Posté par  . Évalué à 2.

      mais toi tu cherche a afficher un char, en mémoire ce n'est pas pareil…

      A part le nombre d'octet, si c'est pareil en memoire : un char est un entier. (sur un octet en general)

  • # get_wch ?

    Posté par  (site web personnel) . Évalué à 1. Dernière modification le 29 mars 2013 à 00:40.

    La fonction get_wch ne permet pas de résoudre ton problème ?

    Sinon, tu peux peut-être essayer d'afficher la valeur du caractère avec %d, ou en hexa avec… %x ? (plus sûre), peut-être que tu pourras mieux voir ce qui se passe (du genre, si ça affiche que la première moitié du caractère UTF-8 ou s'il y a eu une conversion en autre chose, comme latin-1)

    Ah, et sinon, peut-être qu'il y a une histoire de locale à initialiser (setlocale (LC_ALL, "") si ma mémoire est bonne, mais là encore, à vérifier)

    • [^] # Re: get_wch ?

      Posté par  . Évalué à 1. Dernière modification le 29 mars 2013 à 00:46.

      Quand j'ai utilisé get_wch ça ne changeait rien, mis à part que les %d renvoyés étaient différents.
      Quand je tape é avec %d, j'ai la valeur 169 qui apparait.
      Quand j'utilise setlocale(LC_ALL, ""); le code ne compile pas :

      programme.c:58:19: error: expected ‘)’ before string constant
      
      
      • [^] # Re: get_wch ?

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

        Si, si, c'est bien une histoire de setlocale.

        http://blog.freeside.fr/post/2007/03/27/Oisiweb%3A-Comment-afficher-une-chaine-de-caracteres-avec-des-accents

        Si ton caractère "é" vaut 169, c'est que tu es en ISO-8859-1, et pas en UTF-8.

        Le fichier suivant enregistré en UTF-8 fonctionne chez moi (ma distrib est par défaut en UTF-8).

        #include <stdio.h>    /* for printf */
        #include <locale.h>   /* for setlocale */
        
        int main (void)
        
        {
             setlocale (LC_ALL, "");
             printf ("éèâ\n");
             return 0;
        }
        
        
        • [^] # Re: get_wch ?

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

          «Si ton caractère "é" vaut 169, c'est que tu es en ISO-8859-1, et pas en UTF-8.»

          Non, en ISO le caractère 169 correspond au copyright. 169, ça correspond à l'octet de poids faible du code utf-8 de 'é'. Le problème n'est donc pas de ne pas être en utf-8, mais que getch () ne stocke la valeur du caractère utf-8 que sur un octet.

          mistiru:
          Tu dis que si t'utilises get_wch, ça change juste les valeurs que t'affiches avec %d, mais du coup est-ce que ça marcherait pas si t'utilsiais "%lc" au lieu de "%c" pour afficher le caractère ?

          J'ai essayé chez moi, et du coup avec

          get_wch (&ch);
          printw ("char=%lc", ch);
          
          

          (plus le setlocale au début) ça affiche bien les lettres accentuées.

          • [^] # Re: get_wch ?

            Posté par  (site web personnel) . Évalué à 3. Dernière modification le 29 mars 2013 à 12:39.

            Ouaip, je viens d'en faire le constat, j'ai bidouillé en parallèle. J'avais lu en diagonale, j'avais même pas fait gaffe que sa demande était spécifique à ncurses.

            Au final, j'ai modifié son code pour que ça marche, et effectivement, il faut passer par get_wch, ne pas oublier le %lc pour les caractères wide, et L'é' pour définir une constante wide, sans oublier de se lier à ncursesw plutôt que ncurses, ni le setlocale.

            #include <stdio.h>
            #include <stdlib.h>
            #include <ncursesw/ncurses.h>
            #include <locale.h>
            
            wchar_t wch = L'é';
            int err;
            
            int main (int argc, char **argv)
            {
                setlocale (LC_ALL, "");
                initscr();
                raw();
                noecho();
                keypad(stdscr, TRUE);
                while(wch != KEY_F(1))
                {
                    clear();
                    printw("char=%lc", wch);
                    refresh();
                    err = get_wch(&wch);
                }
                endwin();
                return 0;
            }
            
            

            Et le fichier CMakeLists.txt que j'ai utilisé pour compiler:

            project (CURSES)
            cmake_minimum_required (VERSION 2.8)
            
            find_package (PkgConfig REQUIRED)
            pkg_check_modules (NCURSESW REQUIRED ncursesw)
            
            include_directories (${NCURSESW_INCLUDE_DIRS})
            link_directories (${NCURSESW_LIBRARY_DIRS})
            add_executable (curses main.c)
            add_definitions (${NCURSESW_CFLAGS_OTHER} -g -Wall)
            target_link_libraries (curses ${NCURSESW_LIBRARIES})
            
            
  • # é

    Posté par  . Évalué à 1.

    Je viens d'essayer ça :

    #include <stdio.h>
    #include <stdlib.h>
    #include <ncurses.h>
    
    char ch = 'é'; //<----------------- ceci est la ligne 58 (j'ai plein de commentaires au dessus ^^)
    
    int main(int argc, char **argv)
    {
          initscr();
          raw();
          noecho();
          keypad(stdscr, TRUE);
          while(ch != KEY_F(1))
          {
                clear();
                printw("char=%c", ch);
                refresh();
                ch = getch();
          }
          endwin();
          return 0;
    }
    
    

    Et à la compilation, j'obtient :

    programme.c:58:11: warning: multi-character character constant [-Wmultichar]
    programme.c:58:1: warning: overflow in implicit constant conversion [-Woverflow]

    • [^] # Re: é

      Posté par  (site web personnel) . Évalué à 2. Dernière modification le 29 mars 2013 à 11:05.

      Tu auras ce genre d'erreurs si tu sauves ton fichier dans un charset où ce caractère prend plus d'un seul caractère. En gros en ISO-8859-1, 'é' prend un octet, mais en UTF-8, 'é' prend deux octets, il ne tient donc pas dans un char !

      Il faut alors définir une chaîne de caractères, et plus juste un caractère…

  • # Alors voici mes 2cts

    Posté par  . Évalué à 2.

    Alors, en unicode 16 (utf16) un caractère simple est codé sur 16bits.
    Par contre je pense que dans ce cas la
    printw("char=%c", ch)
    est incorrecte et qu'il faut le remplacer par
    printw(L"char=%lc", ch)
    pour signifier au compilo que la chaine de paramètre est aussi en 16bits.

    char ch = 'é'; //<----------------- ceci est la ligne 58 (j'ai plein de commentaires au dessus )

    Normale, un char fais 8 bits, le séparateur ' indique un caractère simple (donc 8 bits aussi) mais le é est codé sur 16 bits donc overflow.

    Je te laisse essayer.

  • # Merci !

    Posté par  . Évalué à 0.

    Merci à tous le monde, le souci est résolu.
    J'utilise donc get_wch, et %lc
    Le problème de compilation venait du fait que j'avais mis le setlocale avant le int main(…
    Encore merci à tous le monde pour cette aide rapide et précise !

Suivre le flux des commentaires

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