Page 1 of 2

wxString::Format uint64_t problem

Posted: Wed Feb 01, 2006 11:39 pm
by aval57
To the wxperts out there,

uint64_t seems to throw wxString::Format out of whack, e.g.

Code: Select all

#include <cstdlib>
#include <iostream>
#include <wx/string.h>

using namespace std;

template<class T> 
void echo( T i, const char *s )
{
   cout << wxString::Format( "%Lu %s ", i, s ) << "\n";
}

int main(int argc, char *argv[])
{
   echo( (uint32_t)2, "hello world" );
   echo( (uint64_t)2, "hello world");
   system("pause");
}

// output:
//    2 hello world
//    2 (null) Press any key to continue . . .
Why is this?

Thanks,
Bahman

Posted: Thu Feb 02, 2006 2:42 pm
by chris
Hi aval57,

a shot in the dark: Could it be that you provide the wrong modifier? "L" denotes a long double afaik.

HTH, Chris

Edit: On a second thought: %lu should work.

Posted: Thu Feb 02, 2006 3:11 pm
by aval57
Hi Chris,

Makes no difference, template or not. I've tried all the modifiers in simple template-free cout statements, and the 64bit type always causes the subsequent string to go '(null)'. If it's a problem with the modifier, then a typecast in the template should fix things:

Code: Select all

template<class T> 
void echo( T i, const char *s )
{
   cout << wxString::Format( "%Lu %s ", (uint64_t)i, s ) << "\n";
}
but this only results in
2 (null)
2 (null)
Press any key to continue . . .
I think it's a quirk in the implementation of wxString::Format.

Bahman

EDIT: %lu chokes too. According to Borland BCB5.HLP L "doubles" as:
L (e E f g G ) : A long double
L (d i o u x X ) : An __int64

Posted: Thu Feb 02, 2006 3:42 pm
by chris
Hi aval57,

I just tried it myself (wxGTK 2.6.2 ANSI), gcc 4.0.3 20051201.
Funnily enough, it's the other way around here: the second call works, the first doesn't.
I implemented this with overloaded methods and it works:

Code: Select all

#include <cstdlib>
#include <iostream>
#include <wx/string.h>

using namespace std;

void echo2(uint32_t i,const char *s ){
   cout << wxString::Format( "%u %s ", i, s ) << "\n";
}

void echo2(uint64_t i,const char *s ){
   cout << wxString::Format( "%Lu %s ", i, s ) << "\n";
}

template<class T>
void echo( T i, const char *s )
{
   cout << wxString::Format( "%Lu %s ", i, s ) << "\n"; // line 18
}

int main(int argc, char *argv[])
{
   echo( (uint32_t)2, "hello world" ); // line 23
   echo( (uint64_t)2, "hello world");
   cout << "overloaded: " << endl;
   echo2( (uint32_t)2, "hello world" );
   echo2( (uint64_t)2, "hello world");
}
Output:
579523549316775938
2 hello world
overloaded:
2 hello world
2 hello world
Please note the compiler complains with -Wall:
test.cpp: In function 'void echo(T, const char*) [with T = unsigned int]':
test.cpp:23: instantiated from here
test.cpp:18: warning: format '%Lu' expects type 'long long unsigned int', but argument 2 has type 'unsigned int'
A few things:
1: %L is actually correct as it seems (for long longs)
2: I'm surprised that the call with the uint32_t doesn't work. uint32_t is type compatible with uint64_t, so it should work.
3: A plain printf shows the same faulty output as wxString::Format() does, so I doubt it's a bug in wx (wx uses the clibs printf, iirc).

However, going with overloads should help.

Chris

Posted: Thu Feb 02, 2006 3:47 pm
by chris
I should also mention that the output from echo( (uint32_t)2, "hello world" ); varies from call to call, so I guess it's a bad pointer problem here.

Edit: Did you try to do a plain printf("%Lu") on the uint64_t?

Posted: Thu Feb 02, 2006 5:35 pm
by aval57
Whoops, got temporarily banned due to an administrative snafu... I'm back.

Your're onto something, Chris. Printf fails on uint64_t as well, (though cout works ok); and running your code at this end (wxWidgets 2.6.0, DEV-C++ mingw32-gcc-3.4.2) gives
2 hello world
2 (null)
overloaded:
2 hello world
2 (null)
Press any key to continue . . .
I guess the easy fix is to bail out of wxString/printf and use cout instead. Any idea what's causing this, though?

Thanks,
Bahman

Posted: Thu Feb 02, 2006 6:24 pm
by chris
Ok, this is obviously an issue in the C runtime library used by MinGW. If I'm not mistaken, MinGW uses the Visual C++ 6 crt (msvcrt.dll). cout doesn't use the C routines, which may explain why it works there. I guess this isn't a bug, btw. You just need to find out which format types are supported in the MinGW runtime. Unfortunately, they don't seem to be as standartized as they should be :(. I did some googling, but no result.
"man 3 printf" tells me to use "%llu" for unsigned long long int, btw. You could try that too, but don't hold your breath...

Posted: Thu Feb 02, 2006 6:29 pm
by chris
Google good:

From here:
g) Significantly incompatible with Linux C.

For example, printf and scanf of standard C 64-bit %llX and %lld don't yet work, instead you have to write Microsoft C: %I64X and %I64d. Possibly this incompatibility is a natural consequence of building .exe that work without installing a Cygwin .dll: the C programming language resists in many ways if you try to add your own % escapes to printf and scanf.
Edit: Hey, they have a wiki over there at MinGW:
http://www.mingw.org/MinGWiki/index.php/long%20long

That should do the trick!

Posted: Thu Feb 02, 2006 6:54 pm
by aval57
Awesome, Chris, this is the full answer, no doubt.

(The joke is I ran across -I64 yesterday, misread it as -EllSixtyFour and therefore got no result :)

Unhappily although

Code: Select all

printf( "%I64u %s", (uint64_t)2, "hello world\n" );
works fine,

Code: Select all

cout << wxString::Format( "%I64u %s", (uint64_t)2, "hello world\n" );
crashes the program, so it looks like it's time to call it a day.

Thanks,
Bahman

Posted: Thu Feb 02, 2006 7:04 pm
by chris
aval57 wrote: (The joke is I ran across -I64 yesterday, misread it as -OneSixtyFour and therefore got no result :)
Ah, the good old "Il1"-problem :wink:

Code: Select all

cout << wxString::Format( "%I64u %s", (uint64_t)2, "hello world\n" );
crashes the program, so it looks like it's time to call it a day.

Damn, I thought we'd solved it. Well, perhaps I'll have a look at the source for wxString::Format() tomorrow, maybe there's something useful in there.
If you really need to do this via Format(), you could also try to get a full backtrace on a debug build of wx...

Posted: Thu Feb 02, 2006 7:31 pm
by aval57
No, Format() was just my preferred method, if only because the code is more visually concise (to my eye, anyway). Going by that standard, though, plain old cout, working as it does without any addl typecasts/modifiers/overloads, looks better and better...

Thanks again
Bahman

Re: wxString::Format uint64_t problem

Posted: Thu Feb 02, 2006 8:09 pm
by ABX
aval57 wrote:uint64_t seems to throw wxString::Format out of whack
Different compilers accepts different format for 64 integers so wxWidgets provides own replacement wxLongLongFmtSpec, see http://www.wxwidgets.org/manuals/2.6.2/ ... ongfmtspec for details.

ABX

Posted: Thu Feb 02, 2006 9:52 pm
by aval57
Thanks ABX

Code: Select all

cout << wxString::Format( "%" wxLongLongFmtSpec "u %s", wxULL((uint64_t)2), "hello world\n" );
still outputs
2 (null)
The problem isn't that I can't display the 64 bit integer, but that the string that follows it becomes '(null)'.

Bahman

Posted: Fri Feb 03, 2006 11:24 am
by chris
Hi,

Code: Select all

cout << wxString::Format( "%" wxLongLongFmtSpec "u %s", wxULL(2), "hello world\n" );
crashed for me in wxVsnprintf_ when using the wxMSW 2.6.2 devpak from wxDev-Cpp 6.9beta (MinGW 3.4.2).

To get a useful backtrace I compiled wxMSW 2.6.2 myself, with "configure --disable-shared --enable-debug". No crash, correct output.
So, what does this tell us? And why is wxVsnprintf_ even called? I thought that one would only be used if there was no suitable vsnprintf on the host, but the Visual C++ 6.0 crt has one (at least it says so at MSDN).

Bahman, where does your wx come from? Did you compile it yourself or install a devpak or something?

Edit: Corrected URL.

Posted: Fri Feb 03, 2006 1:44 pm
by aval57
Good morning Chris! Your efforts are way above and beyond the call of duty, but then sometimes one 'catches a bug'.
I have upCase's 2.6.0 devpak and Andre Simon's 2.6.2 devpak. Compiling and running

Code: Select all

    printf( "%" wxLongLongFmtSpec "u %s", wxULL((uint64_t)2), "hello world\n" );
    cout << wxString::Format( "%" wxLongLongFmtSpec "u %s", wxULL((uint64_t)2), "hello world\n" );
with either devpak gave
2 (null)2 (null)
Bahman

PS perhaps you'd like to share your build as a devpak. (how-to)

UPDATE: Also tried NinjaNL's 2.7 devpak - same result on printf, crash on Format().