Skip to content

Oh, Say Can You C?

There is a “bug” here, can you spot it?

dim s as string = "abc" + chrb(0) + "def"
dim c as cstring = s
if s = c then
  msgbox "Yay our software works as we expected!!!!"
  msgbox "BOOOOOO!!!!"
end if

It isn’t a “bug” in the sense that something isn’t working as it should. It’s that its expectations don’t match documented behavior.

In C a “char *” is a “c string” that is NUL terminated. But there are times when you have to recognize that “char *” means “buffer of bytes” and not a C style string (which is also a “char *” but NUL terminated).

And, in Xojo, the conversion from String to CString means “a nul terminated run of bytes”. So, in the example above, S might initially have 7 bytes, abc<NUL>def, once you convert it to a CString you drop the last 4 bytes because of the NUL.

Now imagine you use “string” as “buffer of bytes” like this in Xojo and pass it to a dylib that is expecting “a buffer of bytes” that is X many bytes long”?

Something like:

// suppose foo just counts bytes until it gets to a nul
soft declare function foo lib "my lib" ( s as CString, count as integer ) as integer
dim s as string = "abc" + chrb(0) + "def"
if foo(s, 7) <> 7 then msgbox "OMG something horrible happened and foo killed our string!!!!"

What happens? The buffer you thought you had is truncated when it’s converted to a CString and the call to the DLL fails.

This example fails in a nice detectable way as did the example that inspired this post. But you do have to check for the failure and then be able to determine what caused it.

What happens if it just fails in a silent non-obvious way but does the wrong thing? When you REALLY need a buffer of bytes – use a MemoryBlock.

You really HAVE to see if the DLL you’re using expects a “buffer of bytes” or a “c string”. And hopefully the developer has documented that well enough for you to determine that so you can do the right thing.