Na forum uw-team.org exylum zadał pytanie: "czy znak przy konwersji liczb zmiennoprzecinkowych ("," lub ".") zależy od systemu na jakim pracujemy, ustawień regionalnych itp.?". Ponieważ pytanie mnie zaciekawiło, to trochę poszperałem tu i tam, odpowiedziałem na forum i w końcu stwierdziłem że napisze (metodą Kopiego=Pasta) o tym również tutaj, być może kogoś również to zaciekawi.

Jak się okazuje, "decimal point" w printf/scanf (a także paru innych funkcjach) zależy jest od ustawienia "locale" (ang. miejsce akcji/zdarzenia wg. słownika dict.pl).
Na początku programu jest to kropka - wynika to ze standardu ANSI C (posłużę się C99) oraz dokumentu ISO/IEC 9945-2, ten pierwszy pozwolę sobie zacytować (ISO/IEC 9899:1999 str 205, pkt 7.11.1.1.4 - Locale control):

At program startup, the equivalent of
 setlocale(LC_ALL, "C");
is executed.


Rodzaj locale "C" zdefiniowany jest w drugim dokumencie o którym wspomniałem (niestety nie dysponuje tym dokumentem żeby zacytować, więc musicie uwierzyć mi na słowo że decimal_point jest tam zdefiniowany jako kropka).

Jeżeli programista chce zmienić decimal_point, to używa (wymienionej wcześniej) funkcji setlocale z parametrem LC_ALL lub LC_NUMERIC, oraz wartością locale jaka ma być (nazwą zdefiniowanego i obecnego w ?systemie? wzorca). Może to być np.:

"Polish" - tak pod windowsem nazywa się polski wzorzec (zachęcam do rzucenia okiem na Remarks w MSDN, ponieważ oznaczenie może zawierać kilka parametrów)
"pl_PL.UTF-8" - a tak pod kubuntu (polecenie locale -a w konsoli wypisuje dostępne możliwości)
etc.

Można również podać wartość pustą "", w takim przypadku:

(*nix)
If the second argument to setlocale(3) is empty string, "", for the default locale, it is determined using the following steps:
      1.     If there is a non-null environment variable LC_ALL, the value of LC_ALL is used.
      2.     If an environment variable with the same name as one of the categories above exists and is non-null, its value is used for that category.
      3.     If there is a non-null environment variable LANG, the value of LANG is used.

(Windows)
setlocale( LC_ALL, "" );
   Sets the locale to the default, which is the user-default ANSI code page obtained from the operating system.


Warto również rzucić okiem na:
- http://msdn.microsoft.com/en-us/library/wyzd2bce.aspx - lista funkcji w MSVCRT korzystających z ustawień locale
- Funkcję "localconv"
- Polecenie "localedef" (definiowanie nowych locale'i pod *nixami)
(niestety nie umiem powiedzieć jak się nowy locale pod windą tworzy / moduje istniejący, ale sądzę że zainteresowani sobie znajdą ;>)

Na koniec jakiś kod przykładowy który napisałem chwilę temu:

#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<locale.h>

int
main(void)
{
 float f = 12.3456;

 printf("Current decimal_point: %s\n", localeconv()->decimal_point);

 setlocale(LC_ALL, "");
 printf("Current decimal_point: %s\n", localeconv()->decimal_point);  
 printf("Current: %f\n", f);

 setlocale(LC_ALL, "en_US.utf8"); // "English" on windows
 printf("Current decimal_point: %s\n", localeconv()->decimal_point);  
 printf("English: %f\n", f);

 setlocale(LC_ALL, "pl_PL.utf8"); // "Polish" on windows
 printf("Current decimal_point: %s\n", localeconv()->decimal_point);  
 printf("Polish: %f\n", f);

 // To nie zadziala ;>
 localeconv()->decimal_point = strdup("_hi_");
 printf("Current decimal_point: %s\n", localeconv()->decimal_point);  
 printf("Polish: %f\n", f);

 return 0;
}


I tyle ;>

Comments:

2009-11-15 19:53:49 = Tomek Z.
{
Przy printf to mało przeszkadza, ale przy atof można się nieźle naciąć. Np. gdy się tworzy międzyplatformowy kod czytający np. format NMEA...
http://stackoverflow.com/questions/1333451/c-locale-independent-atof
}
2009-11-16 12:24:53 = Malcom
{
Naciac to sie mozna prawie wszedzie, szczegolnie przy crossplatformowych zabawkach, trzymajacych dane w czystym tekscie, vide config w XML, czego ostatnio sam doswiadczylem ;)
}

Add a comment:

Nick:
URL (optional):
Math captcha: 7 ∗ 9 + 7 =