How does this line in the String class work?

Hey everybody!

Recently I’ve been trying to reverse engineer the JUCE String class for learning purposes.
I get most of it, but there is just one line in there that has been bugging me for a week now.
I don’t understand how it could possibly work, yet it does…
I was wondering if someone here maybe knows what’s going on and why it works…

On line 216 of juce_String.cpp:

static inline StringHolder* bufferFromText (const CharPointerType text) noexcept
{
// (Can’t use offsetof() here because of warnings about this not being a POD)
return reinterpret_cast<StringHolder*> (reinterpret_cast<char*> (text.getAddress())
- (reinterpret_cast<size_t> (reinterpret_cast<StringHolder*> (128)->text) - 128));
}

I think we’re trying to acces the underlying StringHolder of which the CharPointer is a part,
so we can either reference the same text in a copy or delete the string if the reference count is 0… (correct me if I’m wrong)

What’s bugging me is: reinterpret_cast<StringHolder*> (128)->text … How can we interpret a r-value of 128 as a StringHolder* …?
Also, why do we then subtract 128 from it?

Thank you in advance!

It boils down to the fact that pointers are integers.

reinterpret_cast<StringHolder*>(128) means “please consider that at position 128 in memory there is a StringHolder object”. In reality there is no StringHolder object at that position in memory, but we ask the compiler to behave as if.

Then, we “access” the text member and interpret it as a size_t, which effectively gives us its position in memory. When building and debugging a Windows x64 application on VS2017, I got 144.

Finally, we subtract 128 from 144, to get the offset between the position of the imaginary StringHolder object and the position of its text member. In my case it was 144 - 128 = 16.

Because the layout of the StringHolder class cannot change at runtime, we know that 16 is not just the offset between that imaginary StringHolder object and its text member, but also between any StringHolder object and its respective text member.

Now we can use that knowledge to flip the problem around and figure out the position of the StringHolder object from the position (AKA address) of the text member (which is what the whole function is about).

Using 128 in the first place is quite arbitrary, and the JUCE code was using 1 until August 2017:

I hope this helps you understand better what is happening in this function. Don’t hesitate to ask more questions!

5 Likes

Oh Wow, that actually makes sense… Thank you so much for explaining @McMartin!

Hello and welcome to the forum!

Just a suggestion: to preserve formatting and have a nice monospaced font when writing code snippets, prepend each line of the code with 4 spaces or put 3 backticks ` before and after the whole code block to make it more readable like this:

static inline StringHolder* bufferFromText (const CharPointerType text) noexcept
{
    // (Can’t use offsetof() here because of warnings about this not being a POD)
    return reinterpret_cast<StringHolder*> (reinterpret_cast<char*> (text.getAddress()) - (reinterpret_cast<size_t> (reinterpret_cast<StringHolder*> (128)->text) - 128));
}

It’s the same as selecting your code snippet when editing, and clicking on the tool button that has this symbol on it: </>