PVOID - Строки для TC++

велась разработка под ПЛК ICP DAS I-7188XAD и писать код приходилось на Turbo C++ 1.01. Разработка возможна и на более поздних версиях компилятора до 3.1 включительно...

При виде заголовка возможно сразу появился вопрос: зачем писать очередной класс строки, когда таких написано достаточно, в стандартной библиотеке есть и вряд ли можно сделать лучше?

Очень краткая предыстория: велась разработка под ПЛК ICP DAS I-7188XAD и писать код приходилось на Turbo C++ 1.01. Разработка возможна и на более поздних версиях компилятора до 3.1 включительно, а также на MS VC++ 5, но все же код, сгенерированный этим компилятором, работает наиболее стабильно. Turbo C++, конечно, не Си, однако нет  шаблонов и, соответственно, STL,  а также многих других приятных современных плюшек. Поэтому появилась необходимость создания класса для хранения строк, на основе которого реализованы также класс обработки DCON-запросов и класс для работы с дисплеем контроллера.

Цель:  класс строки, компилируемый на Turbo C++ 1.01, фактически - динамический массив с использованием стандартной библиотеки Си для обработки строк и символов.

Интерфейс: несколько конструкторов, несколько операторов присваивания, конкатенации, преобразование в разнообразные арифметические типы и обратно, обрезка, вырезание частей и т.д.

Использование памяти: учитывая тот факт, что класс создавался для контроллера, имеющего крайне ограниченный объем памяти, использование памяти сведено к минимуму, что в свою очередь ведет к потере производительности. Любое изменение размера строки приводит к вызовам free() / calloc(), и размер буфера не превышает размера хранимых данных. Однако, на практике сколько-нибудь значимого снижения производительности не замечено.

Получилось примерно так:

class CString
{
public:
    // Конструкторы
    CString();
    CString(const CString& s);
    CString(const char* str);
    // Деструктор. Вызывает Destroy();
    ~CString();
    
    // Неявное преобразование в char*
    char* GetString() const;
    // Очищает и выделяет 1 байт под '\0'
    void Clear(); 
    BOOL IsEmpty() const; 
    // Получить целое число из строки. В строке должно
    // находится число в десятичной системе счисления 
    int GetInt() const; 
    static int GetHexInt(const CString& str);
    // То же, что GetInt(), но для шестнадцатеричной
    // системы счисления 
    int GetHexInt() const; 
    float GetFloat() const; 
    // Получить строку из числа 
    static void FromInt(CString& s, int val);
    void FromInt(const int val); 
    static void FromIntHex(CString& s, const int val); 
    void FromIntHex(const int val); 
    static void FromFloat(CString& s, float val); 
    void FromFloat(float val); 
    //Операторы BOOL operator==(const CString& s) const; 
    BOOL operator==(const char* chr) const; 
    BOOL operator!=(const CString& s) const; 
    CString& operator=(const CString& s); 
    CString& operator=(const char* s); 
    CString& operator=(const char c); 
    CString& operator+=(const CString& s); 
    CString& operator+=(char c); 
    CString& operator+=(const char* chr); 
    const CString operator+(const CString& s) const; 
    const CString operator+(const char* s) const; 
    const CString operator+(char s) const; operator char*() const;

    //Манипуляции со строками 
    static BOOL Compare(const CString& s1, const CString& s2, BOOL bCaseSensetive); 
    BOOL Compare(const CString& str, BOOL bCaseSensetive) const; 
    BOOL Compare(const char* chr, BOOL bCaseSensetive) const; 
    static void ToUpper(CString& s); 
    void ToUpper(); void ToLower(); 
    void TrimLeft();
    void TrimRight();
    void Trim();
    BOOL Crop(unsigned int indexFrom, unsigned int indexTo); 
    BOOL Cut(unsigned int indexFrom, unsigned int indexTo); 
protected: 
    // Очистка памяти 
    void Destroy(); 
    // Выделение памяти 
    void Allocate(unsigned int nChars); 
private: 
    // Указатель на массив символов 
    char* m_pString; 
    // Длина строки в символах 
    unsigned int m_nLen; 
};

  Скорее всего, даже такой скромный интерфейс избыточен для работы в ПЛК. При работе с протоколом DCON удобно использовать методы преобразования строки к числу и наоборот.

 Класс небольшой и размещен в одном файле. Теперь можно применить этот класс для обработки аргументов функции main(), например:

#include "VLCSTR.H"

int main(int argc, char** argv)
{
    if(argc>=2)
    {
        CString s(argv[1]);
        int n=s.GetInt();
        //Работа с n...
    }
    return 0;
}

DCON-запросы на модули ввода/вывода  являются ANSI-строками с терминатором \r , поэтому класс CString вполне сгодится для создания класса, создающего запросы на модули, и обрабатывающего ответы от них. Назовем его CDconString...