#include /* using wcsrtombs */ #include /* using realloc, free */ #include /* using memset */ #include /* using fprintf */ #include /* using setlocale */ char* s_wstring_to_string (const wchar_t* ws) { size_t buflen; char* buffer; char* resized; size_t bufpos ; mbstate_t mbstate; memset(&mbstate, 0, sizeof(mbstate)); /* to avoid parsing the string twice, we allocate memory speculatively * with exponential growth. Then we shrink it at the end * * Alternative: use * const wchar_t* tmp = ws; * size_t buflen = wcsrtombs(NULL, &tmp, 0, mbstate); * buffer = malloc(buflen); * wcsrtombs(buffer, &ws, 0, mbstate); * return buffer; */ for(buflen = 4, buffer = NULL, bufpos = 0; ws; buflen *= 2) { size_t converted; if(! (resized = realloc(buffer, buflen))) goto err; buffer = resized; if((converted = wcsrtombs(buffer + bufpos, &ws, buflen - bufpos, &mbstate)) == (size_t) -1) goto err; bufpos += converted; } /* shrink buffer to actually required size */ if(! (resized = realloc(buffer, bufpos + 1))) goto err; return resized; err: free(buffer); return NULL; } int main(void) { setlocale(LC_ALL, ""); char * my_wstr = s_wstring_to_string (L"z\u00df\u6c34\U0001f34c"); if(my_wstr) fprintf (stdout, "%s\n", my_wstr); else puts("Parse failed"); return 0; }