GetDunne Wiki

Notes from the desk of Shane Dunne, software development consultant

User Tools

Site Tools


eliminate_char_arrays

This is an old revision of the document!


Eliminating char[] arrays

Perhaps the biggest weakness of the C programming language is that it has no built-in character-string type. As a results, large chunks of the C Standard Library exist to implement strings using contiguous blocks of char(either arrays or malloc()-allocated chunks on the heap), taking advantage of the fact that the old ASCII code didn't assign a meaning to an all-zeros bit pattern, so an ASCII NUL could be used to terminate “strings” of arbitrary length. This, of course, has resulted in countless man-years of debugging frustration since 1972. I recall reading somewhere that at least one famous computer scientist suggested that C++ was one giant attempt to fix C's lack of a string type.

Unfortunately, C++ didn't have an “official” character-string type either, and because it was originally designed as a proper superset of C, programmers (myself included) kept on using the nasty old null-terminated char array techniques, including all those traditional C Standard Library functions like strcpy, memcpy, memset, and so on. Why? Because it worked, it was reasonably efficient, and the number of available C++ string classes was so bewildering (std::string, added with the C++ Standard Library, being just one more heaped onto the bonfire) that many people just preferred to stick with what they knew.

JUCE includes a perfectly acceptable new String class, which is used widely and highly consistently throughout the entire library, so it makes good sense to use it for all strings in JUCE programs.

Application in the VanillaJuce code

My original implementation of the SynthParameters class was essentially a struct which included a fixed-length char[] array for the program name, like this:

#define kMaxProgramNameLength 24
 
class SynthParameters
{
public:
    char programName[1 + kMaxProgramNameLength];    // 1 extra byte for null terminator
    ...
};

Yes (he said guiltily), I really did use an archaic C #define for the array length. I checked the old VST2.4 SDK to find the maximum program-name length, and dutifully added one more char for the null. I did this because my initial implementation of VanillaJuceAudioProcessor::getStateInformation() etc. actually used memcpy() to make a binary copy the whole parameter-block, and because the VanillaJuceAudioProcessor's programBank member variable is a simple array (also sized using a #define!), so I needed a fixed block size.

Now that I have switched over to using JUCE's very nice XML classes for serializing patch data, the fixed block size isn't as important. Moreover, since the juce::AudioProcessor::getName() function is defined to return a juce::String (presumably truncating it to 24 characters for VST2.4 hosts), I don't even have to worry about the maximum length. Hence it's a no-brainer to us a juce::String for the program name, allowing me to delete the #define:

class SynthParameters
{
public:
    String programName;
    ...
};

The resulting code changes elsewhere, to eliminate clumsy uses of things like sprintf() and juce::String::copyToUTF8()'', etc. are too obvious (and embarrassing) to even list here. ===== Use of const char* for string literals =====

eliminate_char_arrays.1504280354.txt.gz · Last modified: 2017/09/01 15:39 by shane