Rohit Nagpal
Rohit Nagpal

Reputation: 79

Duplicating wide-character string

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

Answers (3)

Kaz
Kaz

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

Remy Lebeau
Remy Lebeau

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

ecatmur
ecatmur

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

Related Questions