Home > Development, MacOSX > Display std::wstring in Xcode using a Data Formatter

Display std::wstring in Xcode using a Data Formatter

July 21st, 2009

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.

Universal Architecture in Xcode

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).

Formatter Display in Xcode

Categories: Development, MacOSX Tags:
  1. August 26th, 2009 at 15:36 | #1

    thank you Philippe, a really useful tip:)

  2. Geoff Smith
    February 15th, 2010 at 13:10 | #2

    Wow – this is making my coding life so much easier – thank you

  3. Nicholaz Beresford
    April 2nd, 2010 at 17:25 | #3

    I played around with this a bit because I wanted to see the actual (non ansi) unicode characters in Xcode.

    I ended up with the code blow. I’m not yet sure if reusing the CFStringRef work, otherwise one would have to return local versions and let them leak.

    #include

    CFStringRef globalRc= 0;

    // Read the DataFormatterPlugin.h header for more information on custom data formatters and allocators requirements
    CFStringRef
    cfstring_for_wchars(const wchar_t *pwchars, size_t charCount, int ident)
    {
    UniChar unibuf[charCount];

    for (size_t i= 0; i<charCount && pwchars[i]!=0; i++) {
    unibuf[i]= pwchars[i];
    }

    if (globalRc) { // Xcode will make a copy of the value, so we can release the last handle
    ::CFRelease(globalRc);
    }

    globalRc= ::CFStringCreateWithCharacters(kCFAllocatorDefault, unibuf, charCount);

    return globalRc;
    }

    CFStringRef
    see_wchar_t(wchar_t thewchar, int ident)
    {
    return cfstring_for_wchars(&thewchar, 1, ident);
    }

    CFStringRef
    see_wchar_t_p(wchar_t *pwchars, int ident)
    {
    return cfstring_for_wchars(pwchars, wcslen(pwchars), ident);
    }

  4. April 2nd, 2010 at 18:56 | #4

    I’m not quite certain of what you are trying to accomplish, I mean Xcode does not display wchar_t characters in its debugger display, that’s why they have to be converted to char.

    Regarding your CFString issue, I would create a CFStringRef and call my functions “create_wchar_t()” instead of “see_wchar_t”, which would make it obvious to the caller that they now “own” the CFString and must CFRelease it themselves.

    Your global will blow up in any multithreaded environment.

  5. Nicholaz Beresford
    April 4th, 2010 at 13:13 | #5

    What I’m trying to accomplish is to actually see unicode characters beyond the Latin glyphs. Returning an CFStringRef which is made from UniChars will for example display Aisan glyphs while the char * version (in my Xcode at least) does only show hex values for non latin characters (the printf works because the console resolves utf8). I.e. I’m passing back CFStrings to Xcode (to be then shown with :s) for full unicode display.

    And yes, I know that the global CFString is a kludge. I have yet to try a cocoa version with autorelease NSString objects instead.

  6. Nicholaz Beresford
    April 4th, 2010 at 13:15 | #6

    E.g. make a wchar_t u[255]= { 0xac00, ‘b’, ‘c’, 0 }; in the test app and see how it outputs.

    The formatter for wchar_t [255] would be
    {see_wchar_t_p((wchar_t *) $VAR, (int) $ID)}:s

  7. Nicholaz Beresford
    April 4th, 2010 at 14:01 | #7

    I have one with pthread protection now. It’s too fiddly to post into this window, if you (or anyone else) is interested, send me an email at nicholaz at blueflash dot cc.

    Otherwise thanks for the post here, it was a very helpful starting point for my own version.

  8. rpv
    April 16th, 2010 at 09:25 | #8

    should i ignore those warnings?

    [WARN]warning: no rule to process file ‘$(PROJECT_DIR)/myCustomFormatter.ccpp’ of type text for architecture x86_64
    [WARN]warning: no rule to process file ‘$(PROJECT_DIR)/myCustomFormatter.ccpp’ of type text for architecture i386
    [WARN]warning: no rule to process file ‘$(PROJECT_DIR)/myCustomFormatter.ccpp’ of type text for architecture ppc

  9. April 16th, 2010 at 23:34 | #9

    @rpv

    For C++ you want “,cpp” files. Your files are “.ccpp”, which Xcode doesn’t know how to compile.

  10. July 19th, 2010 at 20:46 | #10

    Has anyone ever gotten this to work in an iphone project? Works fine for me within wcharTest in the wchardataformatter project, but in my iphone projects, I see only blank summary fields where I should see the formatted wchar_t data. Any ideas appreciated.

Comments are closed.