Reputation: 79
I am trying to create an application in which I have a function where I am trying to duplicate a wide character string. I am currently using _wcsdup()
, since it is a Windows application and everything is working fine for me. But I need to create a multi-platform function, so _wcsdup()
(which is a Windows function) will not work out for me.
Now, my code looks something like this:
wchar_t* out = _wcsdup(wstring.str().c_str());
where wstring
is a string stream.
Now, I am looking for a common function for both Windows and Linux to make this function work properly.
Upvotes: 1
Views: 773
Reputation: 58598
The traditional way is to have a configuration system in your program which tells you what the platform has and doesn't have:
In some source file dedicated to portability, you have:
#if !HAVE_WCSDUP
wchar_t *wcsdup(const wchar_t *orig)
{
#if HAVE_MICROSOFT_WCSDUP
return _wcsdup(orig);
#else
size_t nwch = wcslen(orig) + 1;
wchar_t *copy = wmalloc(nwch);
if (copy)
wmemcpy(copy, orig, nwch);
return copy;
#endif
}
#endif
In some header file (also included by the above), you have this:
#if !HAVE_WSCDUP
extern "C" wchar_t wcsdup(const wchar_t *);
#endif
to provide the missing declaration. A possible approach also is this. In the header file, you do:
#if HAVE_WCSDUP
// nothing to provide
#elif HAVE_MICROSOFT_WCSDUP
// just alias to the Microsoft one via #define
#define wcsdup _wcsdup
#else
// declare ours: provided in portability.cc
extern "C" wchar_t wcsdup(const wchar_t *);
#endif
Then in portability.cc
:
#if !HAVE_WCSDUP && !HAVE_MICROSOFT_WCSDUP
wchar_t *wcsdup(const wchar_t *orig)
{
size_t nwch = wcslen(orig) + 1;
wchar_t *copy = wmalloc(nwch);
if (copy)
wmemcpy(copy, orig, nwch);
return copy;
}
#endif
You need a build configuration system around you program to supply the values of these HAVE_
constants. On some systems, a shell script can inspect the environment and throw them into a config.h
. For some systems, you can have canned configurations; e.g. the configuration step for building on Windows might consist of copying a hand-maintained config-msvc.h
to config.h
. In config-msvc.h
you have:
#define HAVE_MICROSOFT_WCSDUP 1
I'm assuming that you need a malloc
-duplicated string due to communicating with some API that consumes one. Therefore in my answer I have refrained from pontificating about using C++ library features to solve the problem.
However, in C++ code we should probably be referring to the C functions as std::wcslen
and so forth. Or portability.cc
can just be portability.c
, if it is providing missing C functions.
Upvotes: 1
Reputation: 596703
The standard cross-platform equivalent would be to allocate/free a wchar_t[]
buffer using new[]
/delete[]
(or, if absolutely needed, malloc()
/free()
to mirror the behavior of _wcsdup()
), using std::copy()
or std::memcpy()
to copy characters from wstring
into that buffer, eg:
std::wstring w = wstring.str();
wchar_t* out = new wchar_t[w.size()+1];
std::copy(w.begin(), w.end(), out);
w[w.size()] = L'\0';
...
delete[] out;
/*
std::wstring w = wstring.str();
wchar_t* out = (wchar_t*) malloc((w.size() + 1) * sizeof(wchar_t));
std::copy(w.begin(), w.end(), out);
w[w.size()] = L'\0';
...
free(out);
*/
std::wstring w = wstring.str();
size_t size = w.size() + 1;
wchar_t* out = new wchar_t[size];
std::memcpy(out, w.c_str(), size * sizeof(wchar_t));
...
delete[] out;
/*
std::wstring w = wstring.str();
size_t size = (w.size() + 1) * sizeof(wchar_t);
wchar_t* out = (wchar_t*) malloc(size);
std::memcpy(out, w.c_str(), size);
...
free(out);
*/
But, either way, since str()
returns a std::wstring
to begin with, you are better off simply sticking with std::wstring
instead of using wchar_t*
at all:
std::wstring out = wstring.str();
You can use out.c_str()
or out.data()
if you ever need a (const) wchar_t*
, such as when passing out
to C-style functions that take null-terminated string pointers.
Upvotes: 4
Reputation: 157374
Assuming the string needs to be passed to a function that expects to free
it, you can use malloc
and memcpy
:
auto const ws = wstring.str();
auto const ptr = std::malloc(sizeof wchar_t * (ws.size() + 1));
std::memcpy(ptr, ws.c_str(), sizeof wchar_t * (ws.size() + 1));
// pass ptr to another function, or std::free(ptr)
The + 1
is to account for the null terminator, which is not included in size()
.
Upvotes: 0