Problem:
In the C time, we used to use sscanf to read data from string as following:
char strUserName[20], strPassword[20];
// if the content of m_recvBuff is “Microsoft Bill”.
sscanf((const char *)m_recvBuff, “%s %s”, strUserName, strPassword);
And when you first get CString in sight, you may write the similar code:
CString strUserName, strPassword;
// if the content of m_recvBuff is “Microsoft Bill”.
sscanf((const char *)m_recvBuff, “%s %s” , strUserName, strPassword);
Unfortunately, it can not work as you expected and, in most cases, the process will crash.
Solution:
First, you should not be using sccanf, since this is not Unicode-aware. You should use _stscanf which allows for Unicode. In addition, it is not a “safe” methodology because it can generate buffer overruns.
Second, the problem here is that you are doing something profoundly illegal: you are passing a CString pointer to a call that expects an LPTSTR. You can’t do this. It won’t work, and it surprised me that it merely produces an erroneous result instead of crashing with an access fault, heap corruption assert, or some similar fatal situation.
After all, you can use scanf safely, but you should try to use the new _s versions to make them more “trustworthy”. Here’s some info on it:
http://msdn2.microsoft.com/en-us/library/w40768et(VS.80).aspx
The problem you’re having is that you are not actually passing the buffers
of the CStrings to the scanf function. Take a look at the GetBuffer()
function in CString. Also, this function might be useful to you:
http://msdn2.microsoft.com/en-us/library/k4ftfkd2(VS.80).aspx
In additional, You can cast a CString to type LPCTSTR to get read-only access to the contents of the string. However,
(1) You can’t cast a CString to type LPTSTR to get writeable access. You have to do something like call GetBufferSetLength and make sure you set the buffer large enough.
(2) In variable parameters to sscanf, you can’t expect any casting to be done automatically, you have to code the casts.
But if you take enouth care of your code, sscanf may be not necessarily dangerous. You should check the length of the string and make sure you’ve allocated large enough sizes for your other variables then you won’t have buffer overruns.
At last, in MFC, the following code may be the general solution:
CString strUserName;
CString strPassword;
m_recBuff.Trim(); // remove leading and trailing space
int n = m_recvBuff.Find(_T(” “));
if(n>0) /* has space */
{
strUserName = m_recvBuff.Left(n);
strPassword = m_recvBuff.Mid(n + 1);
strPassword.Trim();
}
Unlike sscanf, which should no longer be considered a viable mechanism for any purpose dealing with string outputs, this actually works and is safe. It will not cause a buffer overrun. You should make it a practice to avoid mechanisms that can cause buffer overrun.
The next paragraph is writen by Joseph M. Newcomer, as reference.
There is no economy in using obsolete and unsafe mechanisms. sscanf is overused and I consider it one of the design errors of the C language. I have never yet found a situation in which I would trust it to do the right thing in the presence of bad input, and the best I can say for it is that it is only suitable for use in the most naively trusting situations possible. I never use it, and I have never used it since I first learned of it. I had, as a beginner, used and trusted such mechanisms in languages I learned in the 1960s, and I quickly learned that such mechanisms are simply not to be trusted. I doubt if I have used such a mechanism since about 1967 or so. It was a bad idea then and it remains a bad idea today. The passage of 40 years does not make a bad idea good.
Tags: CString, sscanf, Win32/MFCPermalink: Code Library - sscanf with CString
Subcribe the update with Google Reader.
3 Responses
Adam Gross
January 2nd, 2009 at 12:30 pm
1As far as I can tell, using _tscanf_s with CString is still bad because CString with UNICODE defined is UTF16 but all of these functions expect UTF8. We either need to convert it or to find some Windows-provided ones that expect UTF16.
support
February 4th, 2009 at 11:07 am
2@Adam Gross You are completely right.
Antonio
March 27th, 2009 at 10:04 pm
3Well, you are casting an object on the stack as if it is a pointer, what do you expect, no crash ?
RSS feed for comments on this post · TrackBack URI
Leave a reply
Category
Recent Posts
Hot Posts
Creative Commons
Code Library