|
OK, I don't know what is going on I have been back here many times and responded to posts but I have NEVER seen this post until right now, even though you made it in MAY. I can miss things but not that many times. Grrrrr...
Anyway I feel terrible that I never gave you a response here. At this point I imagine you have moved on but if not, please let me know. Regardless please accept my apologies for not responding to you sooner but I swear I never saw this post.
-Joe
|
|
|
|
|
I have a program. There are some CString::Format function call, and each Format's argument count are all over 17B
But in your CStdString, the safe Format can only accept at most 17 paremetes.
I don't want to undefine SS_SAFE_FORMAT, what I can do?
|
|
|
|
|
Hi,
I have to say I am surprised that any program ever called Format with more than 17 arguments. I figured that was a pretty safe number.
You could create the overloads yourself. What is the maximum number of arguments passed in? Creating overloads is just matter of copy, paste and edit.
Barring that, you have no choice but to undefine SS_SAFE_FORMAT
My main recommendation would be to not use Format at all but rather to use stringstreams. With stringstreams all the formatting is safe and there is no limit on the number of arguments. Frankly Format() and functions like it that take a variable number of arguments are not a good thing to use anyway. Streams are much better.
-Joe
|
|
|
|
|
I suggest to relpace following code
std::basic_string<char>::traits_type::copy(pDst, pSrc, nChars);
to
#if defined(_MSC_VER) && (_MSC_VER >= 1400) //if MSVC8 and later
std::basic_string<char>::traits_type::_Copy_s(pDst, nDst, pSrc, nChars);
#else
std::basic_string<char>::traits_type::copy(pDst, pSrc, nChars);
#endif
...
and
...
std::basic_string<wchar_t>::traits_type::copy(pDst, pSrc, nChars);
to
#if defined(_MSC_VER) && (_MSC_VER >= 1400) //if MSVC8 and later
std::basic_string<wchar_t>::traits_type::_Copy_s(pDst, nDst, pSrc, nChars);
#else
std::basic_string<wchar_t>::traits_type::copy(pDst, pSrc, nChars);
#endif
to avoid warning:
warning C4996: 'std::char_traits<char>::copy' was declared deprecated
c:\program files\microsoft visual studio 8\vc\include\iosfwd(446) : see declaration of 'std::char_traits<char>::copy'
Message: 'You have used a std:: construct that is not safe. See documentation on how to use the Safe Standard C++ Library
|
|
|
|
|
Some of the old code I am trying to adapt to CStdString is being quirky. There was code that took print format specifications like "%%0.%df",5 and turned it into "%0.5f". Other code existed that took the same concept without the variable. Eg CString::Format("%%.0f");
When I try to do the same thing with CStdString, it seems that without any arguments "%%.0f" doesn't turn into "%.0f".
<br />
CStdString s3;<br />
s3.Format("%%.0f-%%.0f/%%d");<br />
TRACE("%s\n",s3.c_str());
CStdString s4;<br />
s4.Format("%%.0f-%%.0f/%%d",1);<br />
TRACE("%s\n",s4.c_str());
Am I doing something wrong? Is Format("%%d") known to not transform to "%d"?
I know there were better ways to do this, and if I wasn't hesitant jump into Boost and STLPort at the same time I would just switch to Boost.Format with pre-made formatters for this bit of code.
|
|
|
|
|
Wow! That's a great catch. It's a bug by me, not doubt. Sorry about that.
It came about because of my SS_SAFE_FORMAT fix. You can read about WHY I put that code in there (search the header file for SS_SAFE_FORMAT and in the comments you'll find a full explanation. but the long and short of it is I tried to "optimize" the case of calling format with no arguments like this:
void Format(const CT* szFmt)
{
Fmt()
*this = szFmt;
}
Unfortunately, this optimization caused the code to totally leave the string alone. I am not sure if the behavior you are looking for is guaranteed by CString::Format() but since CString::Format() does it, I should to.
You have two options to make this work as you want it
1. QUICK FIX
=============
A very quick fix for it is to go into the header file and comment out the line that says this:
#define SS_SAFE_FORMAT
This will make the code work as it should. Unfortunately it will have the unfortunate side effect of making the following code crash your programs (actually as it should but CString lets you get away with it)
CStdString sName("Joe");
CStdString sMsg;
sMsg.Format(_T("My name is %s"), sName); // CRASH!
With SS_SAFE_FORMAT commented out, you would be forced to re-write the last line in of the following ways
sMsg.Format(_T("My name is %s"), sName.GetString());
sMsg.Format(_T("My name is %s"), sName.c_str());
sMsg.Fromat(_T("My name is %s"), static_cast<PCTSTR>(sName));
2. BETTER FIX
================
A better fix is to rewrite the no-argument overload of the Format() function. The version that looks like this:
void Format(const CT* szFmt)
{
Fmt()
*this = szFmt;
}
Should be rewritten to look like this:
void Format(const CT* szFmt)
{
va_list argList;
va_start(argList, szFmt);
FormatV(szFmt, argList);
va_end(argList);
}
Similarly the overload for Format() that looks like this:
void Format(UINT nId)
{
MYTYPE strFmt;
if ( strFmt.Load(nId) )
{
this->swap(strFmt);
}
}
should be rewritten to look like this
void Format(UINT nId)
{
MYTYPE strFmt;
if ( strFmt.Load(nId) )
{
va_list argList;
va_start(argList, szFmt);
FormatV(strFmt, argList);
va_end(argList);
}
}
-Joe
-- modified at 10:29 Monday 26th February, 2007
|
|
|
|
|
Joe
Are you planning to release an updated version? The changes seem simple enough to make but I thought I would ask.
Thanks,
Kevin
|
|
|
|
|
your article / Class is great, helped me a lot with my project, just a simple unicode linux console application... just letting you know that i really appreciate your work.
keep on coding dude... keep on coding
|
|
|
|
|
Glad you like it. Sorry I did not see your post until now. I have just discovered TWO posts on this page that are very old which I have never seen until now.
-Joe
|
|
|
|
|
I am trying to use STLPort as just headers (no io, no lib) in my project because the VC6 std::map iterators don't work across DLL boundaries. I am also trying to remove other MFC C* classes from the same DLL where I switched to std::map.
Since I am not using STLPort's iostreams, I was running into a problem using stringstream. It would pull MFC's sstream and say basic_streambuf is not defined. So I looked for another way to replace all the CStrings and I found CStdString.
CStdString works great until I put the location of /stlport into the additional include directories. When I do that I get many errors in xlocale, xiosbase, xlocmon & etc starting with:
c:\program files\microsoft visual studio\vc98\include\xlocale(20) : error C2011: 'locale' : 'class' type redefinition
c:\program files\microsoft visual studio\vc98\include\xlocale(410) : error C2011: 'ctype_base' : 'class' type redefinition
c:\program files\microsoft visual studio\vc98\include\xlocale(513) : error C2953: 'ctype' : template class has already been defined
c:\program files\microsoft visual studio\vc98\include\xlocale(513) : see declaration of 'ctype'
I've tried all the combinations of settings I can think of in the STLPort config files. I've read the comments in their config files and in StdString.h. I can't find __STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS in STLport-4.6.2, so I don't know if some new macro is the problem.
One more thing I am doing differently. I do not have /stlport in the vc86 directory. It is a sub-directory in my project folder and I have tried absolute and relative paths to it. (If anyone can tell me how to make $(WkspDir) or an equivalent in the "Additional include directories" field of the C/C++ Preprocessor category, I'd appreciate it.)
Thank you,
Jacob
|
|
|
|
|
I gave in and compiled STLPort and stuck it where it wanted to go. I guess I'll carry stlport_vc646.dll around with the project.
I am still interested in knowing how I could have gotten this to work in "headers only" mode.
|
|
|
|
|
Hi Jacob,
I am not sure why it is telling you that locale has already been defined but the error message should tell you WHERE it is defined. Shall I assume that you are picking up both STLPort's locale and Visual C++'s?
This sounds like a configuration problem. However I have not used STLPort for years so I cannot rightly tell you how to get around it. Are there notes in the STLPort distribution that discuss integrating it with Visual C++
Incidentally, since it seems you are using STLPort just because of the std::map iterator issue, can you simply change your DLL's interface to not require passing them across the boundaries. This is not normally a difficult thing to do unless you are dealing with a massive codebase that already does it.
If you have iterators defined in an exported class' definition, you can always try using the PIMPL (Pointer to Implementation) approach. Google it and you'll see what I mean.
-Joe
|
|
|
|
|
The below stated function raises the following error:
StdString.h [line: 3008]
error: cannot convert 'wchar_t*' to 'char*' for argument '1' to
int ssvsprintf (char*, size_t, const char*, char*)
What is wrong here? What must be done to avoid this error?
The ECLIPSE development environment says that function ssvsprintf is
implemented inline by function vsprintf (and only by this function).
Do we not to have to distinguish in this function which type of character
is passed to the function?
void FormatV(const CT* szFormat, va_list argList)
{
#ifdef SS_ANSI
int nLen = sslen(szFormat) + STD_BUF_SIZE;
ssvsprintf(GetBuffer(nLen), nLen-1, szFormat, argList);
ReleaseBuffer();
#else
Furthermore, the usage of function size() is done once without qualifier
"this". This also is reported as error.
Heinz Zechner
|
|
|
|
|
Hi,
First lets be sure you have the very latest version. It is actually not the one on CodeProject (need to fix that) but may be found here:
http://home.earthlink.net/~jmoleary/code/StdString.zip
Please try this and let me know if you still have problems
-Joe
|
|
|
|
|
I am having an issue with that code block too, but mine looks different then his...
void FormatV(const CT* szFormat, va_list argList)
{
#ifdef SS_ANSI
MYTYPE str;
int nLen = sslen(szFormat) + STD_BUF_SIZE;
ssnprintf(str.GetBuffer(nLen), nLen-1, szFormat, argList);
str.ReleaseBuffer();
*this = str;
Mine has ssnprintf, which is being flagged as undefined. His has ssvprintf. I have the latest StdString.h from your web site Joe, so this is the current state.
The question is, should the this function be using ssvprintf, or should the inline defines (under #if defined (__GNUC__) be changed to the ssnprintf?
|
|
|
|
|
YIKES!
My mistake here totally. So sorry. However the fix is simple:
Edit StdString.h header file and replace any instance of the text ssnprintf with ssvsprintf . That should fix your problem.
I fixed this a while ago but I seem to not have that version on my website. So sorry. This should fix things for both you and Heinz
-Joe
|
|
|
|
|
Hi,
I received this error when I tried to use the StdString.h:
e:\datagen\com\cstdstring\stdstring.h(2766) : warning C4786: '?Format@?$CStdStr@D@@QAEXIABVtemplate-parameter-CAB@ABVtemplate-parameter-CAC@ABVtemplate-parameter-CAD@ABVtemplate-parameter-CAE@ABVtemplate-parameter-CAF@ABVtemplate-parameter-CAG@ABVte
mplate-parameter-CAH@ABVtemplate-parameter-CAI@ABVtemplate-parameter-CAJ@@Z' : identifier was truncated to '255' characters in the browser information
e:\datagen\com\cstdstring\stdstring.h(3940) : see reference to class template instantiation 'CStdStr<char>' being compiled
Can you let me know what causes it? I did some research and found out that the file can not be called from the precompiled header. Is it true?
Thanks,
Phil
|
|
|
|
|
Hi Philip,
This is something I used to see frequently with Microsoft Visual Studio. Expanded template parameters which exceed 255 characters are truncated to that length. The warning is harmless. In your case, you are seeing it due to the multiple template parameters of my special "safe" version of Format. More on that later.
If you want to eliminate this warning it you can put this directive in StdString.h
At the top of the file:
#pragma warning (push)<br />
#pragma warning (disable:4786)
And then, at the bottom of the file
#pragma warning (pop)
This will silence it.
You could also turn off the whole "Safe Format" feature to silence it as well. Just make sure the SS_SAFE_FORMAT is not defined in StdString.h or anywhere else in your code. However that option will require you to be careful when calling the Format() function with CStdString arguments. To be specific, you will not be able to do this:
CStdString sMyName(_T("Joe"));
CStdString sSomeVal;
sSomeVal.Format(_T("My name is %s"), sMyName);
...as it will compile just fine but crash your program. Instead you'll have to be very careful to do cast the string argument to the proper expected "C" type, a const TCHAR*. So you'll be forced to do this:
sSomeVal.Format(_T("My name is %s"), sMyName.c_str());
or this:
sSomeVal.Format(_T("My name is %s"), sMyName.GetString());
or this:
sSomeVal.Format(_T("My name is %s"), static_cast<PCTSTR>(sMyName));
This gets annoying because the code compiles either way but that's the danger of using variadic functions like Format() or sprintf().
-Joe
-Joe
|
|
|
|
|
Thanks Joe for your quick response.
I used the first solution and it fixed the problem. Thank you very much.
Regards,
Philip
|
|
|
|
|
Dear Joe,
I have a similar thing unter Visua Studio 2003. Here are the warnings I get:
StdString.h(2120) : warning C4311: 'type cast' : pointer truncation from 'const void *' to 'unsigned long'<br />
StdString.h(2116) : while compiling class-template member function 'bool CStdStr<CT>::TryLoad(const void *)'<br />
with<br />
[<br />
CT=char<br />
]<br />
StdString.h(3940) : see reference to class template instantiation 'CStdStr<CT>' being compiled<br />
with<br />
[<br />
CT=char<br />
]<br />
StdString.h(2122) : warning C4311: 'reinterpret_cast' : pointer truncation from 'const void *' to 'unsigned long'<br />
StdString.h(2125) : warning C4311: 'reinterpret_cast' : pointer truncation from 'const void *' to 'unsigned long'<br />
StdString.h(2120) : warning C4311: 'type cast' : pointer truncation from 'const void *' to 'unsigned long'<br />
StdString.h(2116) : while compiling class-template member function 'bool CStdStr<CT>::TryLoad(const void *)'<br />
with<br />
[<br />
CT=wchar_t<br />
]<br />
StdString.h(3973) : see reference to class template instantiation 'CStdStr<CT>' being compiled<br />
with<br />
[<br />
CT=wchar_t<br />
]<br />
StdString.h(2122) : warning C4311: 'reinterpret_cast' : pointer truncation from 'const void *' to 'unsigned long'<br />
StdString.h(2125) : warning C4311: 'reinterpret_cast' : pointer truncation from 'const void *' to 'unsigned long'<br />
Can I safely ignore them, i.e. #pragma them away?
|
|
|
|
|
Hello,
I have the following behavior and I think its an error, but honestly I'm not sure:
I have some place a little bit place in the memory, say 12 Bytes, and an wchar_t pointer, (wchar_t * ptr;), pointing to the memory. The memory contains an unicode formated string, meaning every other byte is \0. Lets say it contains 'Hello'.
I have an CStdString object named str, and tried the following expression:
str = (wchar_t *)ptr;
After that, str contains the following:
'Hello???????'
So every string is converted the right way, but it is filled up with '?' to the original size in the memory.
Did I something wrong, or is it an error?
Thanks for any help!
Leo
|
|
|
|
|
Hi Leo,
First of all, please be sure you have the very latest version of the code. That is always available at this link:
http://home.earthlink.net/~jmoleary/code/StdString.zip
Assuming you do have it and the problem still occurs, I would have to say you are doing nothing wrong that I can see. The only think I can think is that the string is not NULL terminated. The final two bytes -- after all the characters and their curresponding null bytes -- should be zero. Are they?
If they are and this problem is not going away, could you email me a very simple program or bit of code which illustrates the problem. In particular I'm looking for something that sets up the 12 bytes with the data. I only ask because in my tests, this does not occur.
-Joe O'Leary
-Joe
|
|
|
|
|
Hello Joe,
thank for your quick reply. It seems like I have to do some homework first. I wrote a little program, as you said, and all works fine. So it is obviously not your class. It must be in the context of my project.
Sorry for not doing my testing homework
Thank you!
Leo
|
|
|
|
|
I think you saw this from one of the debug views in Visual Studio. When I look at the contents of a CStdString in MSVS 2003 I see this. The memory however is correct. EG a string "2003" appears to be "2003"??e, but the memory in the buffer _Bx->_Buf is [0x0032, 0x0030, 0x0030, 0x0033, 0x0000, 0x0000, 0x0000, 0x0000] so seems fine... Prob just the debugger definition of std::string being confused with CStdString...
|
|
|
|
|
Hello,
I'm currently experimenting with huge data and get a problem with the Format function:
<br />
CStdString str;<br />
char *pHuge;
<br />
str.Format("%s", pHuge);<br />
str only contains 1024 characters after that call. It seems like a limitation, but I cannot find any parameter to change it.
I thought about writing str = CStdString(pHuge) (it works fine), but how do I replace str.Format("%S", pHuge) then?
I would appreciate any help.
Thanks!
P.S.: Thanks for sharing such a great class!
|
|
|
|
|