Martin Ba
Martin Ba

Reputation: 38961

printf output not affected by global locale?

I cannot get the printf functions in Visual-C++ (VS 2005) to output thousands separator in my integers.

Note: Comments indicate that this is printf's normal behaviour. However, C++ iostream does insert the thousands separator into numbers (tested with std::stringstream and imbue) so is this purely a feature of iostreams and isn't present in the "C" formatting functions?

Here's the test code:

    setlocale(LC_ALL, ""); // -> User locale
    _locale_t loc = _create_locale(LC_ALL, ""); // -> user locale for *_l version

    struct lconv *pLocalSettings = localeconv();
    printf("Locale is: %s\n", setlocale(LC_NUMERIC, NULL));
    printf("Thousands separator set to : {%s}\n", pLocalSettings->thousands_sep);
    printf("Grouping set to: {%o}\n", int(pLocalSettings->grouping[0]));

    int i = 1000000;
    __int64 i64 = i * 2;
    printf("32 Bit integer output: %d\n", i);
    printf("64 Bit integer output: %I64d\n", i64);
    _printf_l("32 Bit integer output: %d\n", /*locale=*/loc, i);
    _printf_l("64 Bit integer output: %I64d\n", /*locale=*/loc, i64);
    _free_locale(loc);

The output is:

Locale is: German_Austria.1252
Thousands separator set to : {.}
Grouping set to: {3}
32 Bit integer output: 1000000
64 Bit integer output: 2000000
32 Bit integer output: 1000000
64 Bit integer output: 2000000

Upon further checking, it would appear that it doesn't work like this. I tried this:

#include <iostream>
#include <clocale>
using namespace std;

int main() {
    setlocale(LC_ALL, "en_US"); // -> User locale

    struct lconv *pLocalSettings = localeconv();
    printf("Locale is: %s\n", setlocale(LC_NUMERIC, NULL));
    printf("Thousands separator set to : {%s}\n", pLocalSettings->thousands_sep);
    printf("Grouping set to: {%o}\n", int(pLocalSettings->grouping[0]));

    int i = 1000000;
    long long  i64 = i * 2;
    printf("32 Bit integer output: %d\n", i);
    printf("64 Bit integer output: %I64d\n", i64);

    return 0;
}

on http://www.compileonline.com/compile_cpp11_online.php (Can't find no permalink there.)

And the output is:

Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1

Executing the program....
$demo
Locale is: en_US
Thousands separator set to : {,}
Grouping set to: {3}
32 Bit integer output: 1000000
64 Bit integer output: 2000000

Upvotes: 1

Views: 3078

Answers (4)

V-X
V-X

Reputation: 3039

I found IBM printf document, which says the locale affects e, E, f, g, and G conversion characters.

Neither o nor d use locale conversion...

Upvotes: 3

AAAfarmclub
AAAfarmclub

Reputation: 2390

Its possible the OP is getting printf from C mixed up with BASH's printf (which does have some locale features) ??

(I'm on CrunchBang 11 "Waldorf", derived from Debian 7 "Wheezy")

LANG=en_US.UTF-8
LC_NUMERIC not set

For example:

$ printf "%d\n" 12345678
12345678
$ printf "%'d\n" 12345678
12,345,678

BASH printf command
(see Field and printing modifiers)

Upvotes: 0

Martin Ba
Martin Ba

Reputation: 38961

Let me share what I learned here:

  • C locale does contain the information regarding the thousands separator, but this information is not used at all by the printf* family of functions (unless you count the flag extension ', which isn't present in MSVC anyways)
  • C++ locale contains the info as well, and iostreams actually make use of it when formatting numbers (numpunct facet)
  • Setting the global C locale with setlocaledoes not affect the global C++ locale set by std::locale::global()

  • The correct code to get my formatted numbers ended up being:

    static std::locale user_locale("");
    std::wstringstream buf; 
    buf.imbue(user_locale); 
    buf << some_integer; 
    
  • For certain use cases a performance speed-up can be obtained by using the facet directly.

Upvotes: 3

cdev
cdev

Reputation: 807

On pages 90-93 of his book "The Standard C Library", P.J. Plauger presents the code for a function called _Fmtval(), which formats a floating point value using information provided by localeconv(). The caller specifies whether the value should be formatted as international monetary, local monetary, integer or floating point with a specified number of fraction digits. Part of the code handles digit grouping and the insertion of separator characters. This could be used as a guide for writing your own function.

The article at the following link by the same author provides a similar discussion to the book, and presents an almost identical version of _Fmtval(). Unfortunately the code provided with the article seems to contain some OCR errors. If possible refer to the book.

Standard C: Formatting Monetary Values, P.J. Plauger

http://www.drdobbs.com/standard-c/184402377?pgno=4

Upvotes: 1

Related Questions