metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2012-04-22 06:05 pm

C, parse comma-separated line

Кошерен ли такой код для разбиения строки, разделенной запятыми на отдельные строки: http://ideone.com/rhNXq ?

PS: strtok не признаю по идеологическим причинам - она меняет анализируемую строку, что меня крайне пугает, хотя в моем конкретном случае это не мешает.

PPS: безотносительно к strtok, в функции было минимум две ошибки - отсутствие проверки на выход за пределы буфера и попадание eol в последнюю строку (девайсина, с которой приходит строка, терминирует ее \r)

[identity profile] smalgin.livejournal.com 2012-04-22 04:37 pm (UTC)(link)
Как уже предложили выше (lionet), используйте готовую библиотеку строк. Чем раньше вы начнете ее использовать, тем меньше времени потратите на переписывание потом.

Если вам нужно просто разобрать CSV, то и для разбора оного есть готовые библиотеки с хорошей историей.

В строках можно даже с добрыми намерениями нагородить 'one off' и buffer overruns (как вы показательно его вставили в первой же функции сверху)

Еще стандартный совет из сети - не использовать арифметику указателей без сильной нужды. operator[] and indexes do the same job just fine.

Будет весело, гарантирую.

[identity profile] metaclass.livejournal.com 2012-04-22 04:41 pm (UTC)(link)
А где там overrun?

[identity profile] smalgin.livejournal.com 2012-04-22 04:58 pm (UTC)(link)
Я в голове покрутил и там загорелась неонка. :)

int parse_answer(char **buffer_start, char *buffer_end, char **curr_ptr, size_t *curr_size)
{
if(*buffer_start >= buffer_end){
return 0;
}
*curr_ptr = *buffer_start;
while(**buffer_start != ','){
(*buffer_start)++;
}
Где проверка на конец буфера?

(*buffer_start)++;
One-off потому что запятая может быть и последним символом тоже. Вообще на каждом операторе, сдвигающем индекс влево или вправо, нужно неукоснительно проверять boundary conditions. Если сдвиг нетривиален, но инвариантен по отношению к граничным условиям, откомментируйте это в коде. Только так, только двойная итальянская бухгалтерия...

*curr_size=*buffer_start-*curr_ptr-1;

return 1;
}

Вроде так как-то. Код прототипический, так что я не думал заострять на этом внимание более чем в образовательных целях.

PS Я сам грешен, в недавнем коде JSON разбирал именно тупой итерацией по буферу и switch оператором... но уж сильно хотелось самому написать :)

[identity profile] metaclass.livejournal.com 2012-04-22 04:42 pm (UTC)(link)
Холерный вибрион, я ж не проверяю в цикле выход за пределы буфера.

[identity profile] smalgin.livejournal.com 2012-04-22 05:31 pm (UTC)(link)
Не суть, это ж прототип. Я просто пытаюсь донести мысль, что это одна мелочь, которую вы поймали. Еще будет 999.

Как насчет поддержки UTF-16? :)

[identity profile] metaclass.livejournal.com 2012-04-22 05:46 pm (UTC)(link)
Железо строго ASCII и по некоторым политическим причинам никогда в жизни не будет поддерживать что-то кроме этого :)

[identity profile] smalgin.livejournal.com 2012-04-22 05:58 pm (UTC)(link)
Ну, значит, UTF8 :)

Ладно, я гоню уже. Вредно работать по выходным.