Display std::wstring in Xcode using a Data Formatter
std::wstring
: unsafe, but sometimes necessary
When dealing with cross-platform code, especially Windows, it is not uncommon to encounter wchar_t
and its companion string class, std::wstring
.
Unfortunately, Xcode does not display these types natively. Yes, you can add this file to your .gdbinit
file and then you will be able to type:
pwstring mystring
but what you really want is for the values to show up in Xcode’s variable display, and in tooltips.
What you need is called a Custom Data Formatter.
In this post, I will adapt Apple’s sample wchar_t
data formatter and modify it to display std::wstring
variables. I will also explain where you should put this formatter in Xcode 3.1.
Complete source code is available on bitbucket.org, with a MIT license.
Initial Data Formatter
Xcode Data Formatters are simple bundles that are loaded by Xcode at startup. They are essentially plug-ins to extend Xcode.
Starting with Apple’s own wchar_t Data Formatter sample, we immediately notice that:
- This sample is quite outdated, almost 4 years old (the Release build actually builds only PPC!)
- It won’t work as-is with
std::wstring
since it only contains .c files.
We will update this sample to work with std::wstring
and build it as a 4-way universal binary.
Modernizing the Data Formatter
Switching to C++
Since the data formatter will use std::wstring
, we need to build it using C++. Just rename all the .c files to .cpp and voilà!
Modify CustomDataViews.plist
If you open CustomDataViews.plist, you will see that it has one entry per variable type that the formatter can handle. That entry contains a Data Formatter, much like the one you would type in Xcode itself (for example, to display the name of a notification—of type NSNotification—you can use {(NSString *)[$VAR name]}
).
What is different here is the formatter contains a string that calls back in our custom Data Formatter: for example, wchar_t
corresponds to {(char *)myWCharDataFormatter((wchar_t) $VAR, (int) $ID)}:s
.
Add two entries to that plist, for types wstring
and wstring*
, and replace the callback strings with a new unique string, for instance myWStringDataFormatter
and myWStringPointerDataFormatter
. Watch for capitalization, case matters.
Add new callback functions
Now add the two callback functions you referenced in the plist in myCustomFormatter.cpp
:
#include <string> char * myWStringDataFormatter(std::wstring wstr, int identifier) { size_t bufLen = wstr.size() + 1; return dataformatter_char_for_wchar(wstr.data(), identifier, bufLen); } char * myWStringPointerDataFormatter(std::wstring *wstr, int identifier) { size_t bufLen = wstr->size() + 1; return dataformatter_char_for_wchar(wstr->data(), identifier, bufLen); }
As you can see, we are re-using the preexisting wchar_t
code with our std::wstring
.
Build a 4-way Universal Binary
Double-click the wchardataformatter project icon to bring up the Project Inspector. Select the Release configuration, and click the “Architectures” pop-up menu. Select 32/64 bit universal, as shown below.
Modify the Test Code
Finally, update wcharTest_main.cpp
to add new std::wstring
variables to display in the debugger:
#include <stdlib.h> #include <wchar.h> #include <string> int main(int argc, char *argv[]) { wchar_t c = 'A'; wchar_t b[255]; wchar_t *d = &b[0]; char *a = "a b c d e f g"; mbstowcs(d, a , strlen(a)); std::wstring s = L"wide string"; std::wstring *ps = &s; return 0; }
Switch the target to wCharTest in Xcode, set a breakpoint on the last line, and hit “Build and Go”. Xcode should build the test application and stop in the Debugger. Since you have not installed the formatter, you should not see anything special in the Variable Display window.
Installing the Data Formatter
Build the Data Formatter (Debug or Release). Locate the bundle by control-clicking on the “Products / wcharDataFormatter.bundle” in the Xcode project.
Drag the bundle to this folder: ~/Library/Application\ Support/Developer/Shared/Xcode/CustomDataViews
, creating intermediate folders along the way if they do not exist.
You can remove the ~ to install for all users (not just you), and you can also replace “Shared” in the path with “3.0” or “3.1” if you only wanted to install the formatter for Xcode 3.0 or 3.1.
Testing the Formatter
Build the wcharTest target, and set a breakpoint in the main() function of wcharTest_main.cpp. You can step over each line, and you should see your data formatter being called and displaying in Xcode’s Variable Display, as well as in tooltips (Xcode 3.1 and later).