Улучшение моего использования стиля C - PullRequest
3 голосов
/ 05 ноября 2010

Я уже давно занимаюсь моддингом игр Valve, но одна из них, в которой я никогда не был хорош, - это использование массивов символов для манипулирования строками.Я действительно хотел бы улучшить, учитывая, сколько времени я трачу на них.Очевидно, что использование правильных Strings было бы неплохо, но, поскольку все функции SDK возвращают char * или принимают его как аргументы, с тех пор он мало что делает для преобразования обратно и четвертого.У кого-нибудь есть хорошие ссылки, чтобы лучше понять их?Большая часть того, что я нахожу в Google, это просто фрагменты.

Также я пытаюсь разобрать очень простой текстовый файл.В основном содержимое выглядит следующим образом ...

PatchVersion = 1.1.1.2 ProductName = l4d appID = 440

Я хочу получить PatchVersion и ProductName.Мой код выглядит примерно так, но на самом деле просто отсутствие должных знаний оставило меня в тупике.strtok извлекает токен только перед знаком '=', strchr дает мне указатель на его местоположение, но просто не знает хорошего метода.

bool ParseSteamFile()
{
    FileHandle_t file;
    file = filesystem->Open("steam.inf", "r", "MOD");

    if(file)
    {
        int size = filesystem->Size(file);
        char *line = new char[size + 1];

        while(!filesystem->EndOfFile(file))
        {
            char *subLine = filesystem->ReadLine(line, size, file);
            Msg("SUBLINE: %s\n", subLine);

            char *buffer = "";

            if(strstr(subLine, "PatchVersion"))
            {
                char *c = strtok(subLine, "=");
                while(c != NULL)
                {
                    Msg("Token: %s\n", c);
                    c = strtok(subLine, "=");
                }
            }
        }
    }
}

Ответы [ 4 ]

2 голосов
/ 05 ноября 2010

Нет ничего плохого в использовании C-строк.Однако для этого потребуется написать довольно немного низкоуровневого кода, который уже абстрагировался при использовании объектов String.

Как правило, C-String - это просто массив байтов (каждый байт).соответствует значению символа ascii) с нулевым байтом в конце.Фактический синтаксис команд, однако, может быть немного эзотерическим, я рекомендовал cplusplus.com в качестве справочного.

Ваш второй вызов strtok должен быть вызван с нулем, а не снова с подлиней:1006 *

В данный момент вы токенизуетесь по знаку равенства, поэтому вы получите:

PatchVersion
=1.1.1.2 ProductName
=l4d appID
=440

Не забывайте, что strtok потребляет входную строку, поэтому subLine будет пуста, как только выЦикл завершается.

Я бы начал с токенизации строки пробелами, чтобы получить каждую пару ключ-значение.Затем я разделил бы каждую пару ключ-значение на составляющие ее элементы и сохранил нужные.Функция (s) scanf может очень хорошо выполнить этот тип анализа.Чтобы прочитать одну пару в name и value:

char * name = new char[255];
char * value = new char[255];
sscanf(subLine, "%s=%s", name, value);

Затем вы можете использовать strncpy, чтобы скопировать значение в соответствующее место.sscanf не использует входные данные, поэтому последующие вызовы должны будут переместить указатель subLine дальше предыдущего соответствия (или использовать три пары% s =% s в выражении формата вместе с тремя парами переменных name и value, если вы знаете,всегда будет три).

Важно, чтобы код вашего приложения был как можно дальше от операций низкого уровня, насколько это разумно.Если вы часто делаете этот тип манипуляции, поиск или создание библиотеки, которая анализирует такие файлы, может быть хорошей (и забавной) идеей.

2 голосов
/ 05 ноября 2010
sscanf(*subLine, "PatchVersion=%s ProductName=%s appID=%d", patchVersion, productName, &appID);

Вам нужно будет указать переменные соответствующим образом, я надеюсь, что указатель правильно, в противном случае настройте соответственно. источник

0 голосов
/ 05 ноября 2010

Возможно, вы захотите взглянуть на библиотеку Boost's String Algorithms, которая обеспечивает функциональность, аналогичную std::string exposes для произвольных последовательностей символов, таких как строки C.

0 голосов
/ 05 ноября 2010

Очевидно, что использование правильных Strings было бы неплохо, но, поскольку все функции SDK возвращают char * или принимают его как аргументы, с тех пор он мало что делает для преобразования обратно и четвертого.

У

строк есть конструктор и оператор = из const char *, поэтому очень легко хранить результаты функции SDK в виде строк, а функция-член .c_str () позволяет передавать результаты строк в качестве аргументов функций SDK. Действительно, когда ваши требования к производительности не так высоки, что вам нужно избегать использования кучи, std :: string стоит использовать только для того, чтобы автоматически увеличивать его в соответствии с данными, которые вы обрабатываете, и освобождать память при выполнении строки выходит за рамки. Вы склонны избегать множества мелких ошибок и ограничений, используя std :: string. Вы можете кодировать строки в стиле C, используя asprintf () (если ваша система предоставляет это, в противном случае некоторые хакерские действия с sprintf () и / или snprintf (), malloc (), realloc () и т. Д.) И использовать smart-указатели для безопасное исключение и автоматическое освобождение памяти, но это все еще неуклюже. Строковые потоки также стоит использовать для разбора ввода и форматирования вывода ... у них есть член .str (), и вы можете связать .c_str () с этим, чтобы получить константный символ *.

Если вам нужны уровни производительности с переменной стека (и вы не против иметь верхний предел размера данных или откат к куче для больших строк), используйте функцию sscanf(), упомянутую в других решениях. Вы уже получили хороший совет по токенизации входных данных пробелами, после чего вы можете использовать strchr, чтобы найти первый '='.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...