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 Anonyme . Évalué à 2.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: info
Posté par cfx . É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 Anonyme . Évalué à 1.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: info
Posté par cfx . É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 Anonyme . Évalué à 2.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: info
Posté par cfx . É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/
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.
[^] # Commentaire supprimé
Posté par Anonyme . Évalué à 1.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: info
Posté par cfx . É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 cfx . É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.