Forum Linux.debian/ubuntu [Résolu] Problème de séparateur décimal

Posté par  . Licence CC By‑SA.
Étiquettes :
1
15
oct.
2013

Salut à tous,

J'ai une machine virtuelle et un serveur sur lesquels j'ai installé des Ubuntu 12.04 (LTS donc), qui sont configurées plus ou moins de la même façon (package, environnement…).
Je tente d'y faire tourner un programme développé en C++ et compilé par mes soins et qui utilise boost::program_options pour gérer les options de la ligne de commande : ./pouet -l 42.5
Sur la machine virtuelle, tout fonctionne comme prévu.
Sur le serveur, il faut que je change le séparateur décimal pour une virgule : ./pouet -l 42,5 . Ou bien que je force export LC_NUMERIC=C.

Pourtant, sur les deux installations, les locales semblent bonnes :

$ locale
LANG=fr_FR.UTF-8
LANGUAGE=fr:en
LC_CTYPE=fr_FR.UTF-8
LC_NUMERIC="fr_FR.UTF-8"
LC_TIME="fr_FR.UTF-8"
LC_COLLATE=fr_FR.UTF-8
LC_MONETARY="fr_FR.UTF-8"
LC_MESSAGES=fr_FR.UTF-8
LC_PAPER="fr_FR.UTF-8"
LC_NAME="fr_FR.UTF-8"
LC_ADDRESS="fr_FR.UTF-8"
LC_TELEPHONE="fr_FR.UTF-8"
LC_MEASUREMENT="fr_FR.UTF-8"
LC_IDENTIFICATION="fr_FR.UTF-8"
LC_ALL=

Et si je compile et exécute ces quelques lignes ce C, tout va bien :

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
        double a = atof("42.5");
        printf("%lf\n", a);

        return 0;
}

Si l'un d'entre vous à une idée, je suis preneur.

  • # Commentaire supprimé

    Posté par  . Évalué à 2.

    Ce commentaire a été supprimé par l’équipe de modération.

    • [^] # Re: info

      Posté par  . Évalué à 0.

      En effet, il manquait l'info comme quoi la commande locale retourne la même chose sur les 2 machines.
      Ainsi que celle disant que si, sur le serveur, je force LC_NUMERIC=C, je peux utiliser le point comme séparateur décimal.

      La configuration des deux machines est sensiblement identique.

      Oui, en français le séparateur décimal est la virgule. Mais mis à part les tableurs qui sont relativement sensibles sur ce point, je n'ai jamais tapé de nombre décimaux avec une virgule dans mon terminal.

      De ce que je me souviens, atof() utilise par défaut la locale C, qui justement spécifie le point comme séparateur décimal.

      Du coup, c'est plutôt le comportement de ma machine virtuelle qui me parait être le bon.

      • [^] # Commentaire supprimé

        Posté par  . Évalué à 1.

        Ce commentaire a été supprimé par l’équipe de modération.

        • [^] # Re: info

          Posté par  . Évalué à 0. Dernière modification le 15 octobre 2013 à 19:34.

          C'est moi qui parse la valeur, à coup de strtof() (parce que les strtoX() sont les seules méthodes qui permettent de vérifier que ce que l'on a obtenu est correct (sans avoir à sortir l'artillerie lourde, genre boost::lexical_cast)).

          Du coup, j'ai tenté de vérifier ma locale juste avant l'appel à strtof().

          D'après http://www.cplusplus.com/reference/locale/locale/locale/, en C++ :
          std::locale g = std::locale(); est sensé me donner ma locale globale (pas certain de ce que cela signifie),
          std::locale d = std::locale(""); est sensé me donner la locale par défaut du système,
          std::use_facet< std::numpunct >(la_locale).decimal_point(); est sensé me donner le séparateur décimal.

          Sur les deux machines, la locale par défaut est C avec comme séparateur décimal est le point, et la locale globale est bien fr_FR.UTF-8 avec la virgule. Mais je ne suis pas certain de savoir laquelle est utilisée…

          Sauf qu'à priori, comme strtof() est une fonction C et non C++, elle utilise une autre locale.
          D'après http://www.cplusplus.com/reference/clocale/localeconv/, les lignes suivantes me donne le séparateur décimal :

          struct lconv * lc = localeconv();
          std::cout << lc->decimal_point << std::endl;

          Sur ma machine virtuelle, c'est bien le point. Sur le serveur, c'est la virgule. Ce qui explique le comportement du serveur. Reste à trouver pourquoi il utilise une locale différente. Moi qui avait pris une LTS en pensant être tranquille…

          Je pense qu'en attendant, je vais changer pour du lexical_cast.

          • [^] # Commentaire supprimé

            Posté par  . Évalué à 2.

            Ce commentaire a été supprimé par l’équipe de modération.

            • [^] # Re: info

              Posté par  . Évalué à 0.

              Non, la locale par défaut qui est sensée être utilisée par un programme en C est la locale "C".
              Source : http://www.cplusplus.com/reference/clocale/

              The "C" locale is the minimal locale. It is a rather neutral locale which has the same settings across all systems and compilers, and therefore the exact results of a program using this locale are predictable. This is the locale used by default on all C programs.

              J'ai testé sur deux autres machines (Debian stable et testing), toutes les deux configurées avec du fr_FR.UTF-8 comme locale, et le comportement celui que j'ai toujours vu : c'est le point qui est utilisé comme séparateur décimal.

              #include <stdio.h>
              #include <stdlib.h>
              #include <locale.h>
              
              int main(int argc, char** argv)
              {
                      float v;
                      char *l;
              
                      if(argc == 1) {
                              printf("Usage: %s 3.14\n", argv[0]);
                              return -1;
                      }
              
                      /* Get the name of the current locale.  */
                      l = setlocale (LC_NUMERIC, NULL);
                      printf("Locale used: %s\n", l);
              
                      v = strtof(argv[1], 0);
                      printf("The first argument is: %f\n", v);
              
                      return 0;
              }
              • [^] # Commentaire supprimé

                Posté par  . Évalué à 1.

                Ce commentaire a été supprimé par l’équipe de modération.

        • [^] # Re: info

          Posté par  . Évalué à 0.

          Bon, en fait c'est juste dix fois plus simple d'utiliser boost::lexical_cast que des strtoX().

  • # Problème résolu

    Posté par  . Évalué à 1.

    Et le coupable est : Qt.

    Il me manquait un commit sur la version que je compilais sur ma machine virtuelle.

    Commit qui transformait mon application console en application console Qt.

    Et Qt charge la locale du système, donc fr_FR.UTF-8.
    http://harmattan-dev.nokia.com/docs/library/html/qt4/qcoreapplication.html#locale-settings

    Merci à toi Francesco d'avoir pris un peu de son temps pour essayer de m'aider.

Suivre le flux des commentaires

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