Visual C++ in Short: Converting between numbers and strings
C++ developers have a number of options available to them for converting between numbers and strings, few of which are very appealing. Most developers are familiar with the likes of atoi and itoa from the C Run-Time Library. The main problem is that these functions don’t have a coherent way of reporting errors. Although there have been some attempts to improve these functions, most notably the addition of the security enhancements introduced by Microsoft, they are still not very helpful.
Fortunately the Windows SDK includes a very comprehensive collection of functions that it inherited from OLE Automation to convert between variant-compatible types. These functions don’t actually require you to use variants or even initialize OLE or COM. They merely provide the functionality for converting between many of the types that you could store in a variant.
The functions are declared in OleAuto.h and take the form VarXxxFromYyy where Xxx is the desired type and Yyy is the original type of the data. You can use “Var[^ ]+From[^ (]+” to search for them from within Visual Studio.
The functions for converting strings to numbers are prototyped as follows:
HRESULT VarXxxFromStr(const WCHAR* string, LCID localeId, ULONG flags, T* number);
The source is a pointer to a Unicode string (and does not have to be a BSTR). The locale identifier affects how the string is interpreted. You can for example use the user’s regional settings as defined by the current thread’s locale identifier using the GetThreadLocale function. Alternatively you can specify LOCALE_INVARIANT if you need the conversions to be independent of the user’s locale. This might be the case if you’re using the text form of a number not to display to the user but rather to persist in some format like XML. The flags are mostly for controlling date and time conversions and should be zero in most other cases.
The following example shows how to convert a string to a double in a locale-independent manner:
double value = 0;
const HRESULT result = ::VarR8FromStr(L"1234.567",
LOCALE_INVARIANT,
0, // flags
&value);
if (FAILED(result))
{
// The HRESULT describes why the conversion failed,
// e.g. DISP_E_TYPEMISMATCH, DISP_E_OVERFLOW
}
ASSERT(1234.567 == value);
The functions for converting numbers to strings are prototyped as follows:
HRESULT VarBstrFromYyy(T number, LCID localeId, ULONG flags, BSTR* string);
These functions all return the strings as BSTR values so the caller is responsible for freeing them using the SysFreeString function. A better approach is to use ATL’s CComBSTR wrapper class.
The following example shows how to convert a double to a string using the locale associated with the current thread and then converts the string back to a double again:
#include <atlbase.h>
#define ASSERT ATLASSERT
int main()
{
double double1 = 1234.567;
CComBSTR string;
HRESULT result = ::VarBstrFromR8(double1,
::GetThreadLocale(),
0, // flags
&string);
if (FAILED(result))
{
// The HRESULT describes why the conversion failed,
// e.g. E_OUTOFMEMORY
}
double double2 = 0;
result = ::VarR8FromStr(string,
::GetThreadLocale(),
0, // flags
&double2);
if (FAILED(result))
{
// The HRESULT describes why the conversion failed,
// e.g. DISP_E_TYPEMISMATCH, DISP_E_OVERFLOW
}
ASSERT(double1 == double2);
}
Keep in mind that the thread locale can change at any time so you must not persist a localized version of a number as you may not be able to parse it later on. It is however useful for displaying and accepting input from the user.
If you’re looking for one of my previous articles here is a complete list of them for you to browse through.
Produce the highest quality screenshots with the least amount of effort! Use Window Clippings.