Приведение строки C между библиотеками - PullRequest
1 голос
/ 08 октября 2011

Я работаю над проектом, использующим libpcap для захвата IP-пакетов. libpcap возвращает захваченные данные в буфере с указателем unsigned char * и длиной буфера. Данные в буфере не заканчиваются нулем.

Я обрабатываю данные буфера с помощью библиотечных функций, например, строковые функции из стандартной библиотеки C. Эти функции предполагают (подписанные) char * указатели, требующие приведения данных между unsigned char * и char *.

Мне нравится идея предположить, что буфер unsigned char * не имеет нулевого конца (сопровождается длиной буфера) с потенциально непечатаемыми символами, в отличие от буфера char *, который содержит строковый литерал для печати. Однако это вынуждает меня приводить буфер libpcap для каждого вызова строковой функции, что делает код ужасным.

Каким будет ваш стиль кодирования в этом случае?

  • Сохранять unsigned char * и приведение при вызове строковых функций.

  • Преобразуйте буфер libpcap в char * сразу после получения его из libpcap и различаются между необработанными данными и строками с помощью соглашений об именах переменных в исходном коде.

Ответы [ 4 ]

1 голос
/ 09 октября 2011

Если вы знаете, что находитесь на уровне протокола, где должен быть текст, используйте второй подход, просто держите символ * и используйте его там, где это необходимо. Нет повода бросать его на символ * везде.

Однако будьте очень, очень, очень осторожны в отношении того, какие функции обработки строк вы используете. Вы захватываете вещи с провода, вы можете получить что угодно. то есть вы должны соблюдать общую длину буфера, предоставляемого pcap, везде - такие функции, как strlen, strcpy и т. д. не могут использоваться, если вы не измените и не завершите буфер безопасно. (и вам действительно нужно выполнить проверку работоспособности, если, например, вы анализируете длину UDP-пакета и длина говорит о 130 байтах, это не значит, что на самом деле есть 130 байтов, к которым вы можете безопасно обращаться)

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

0 голосов
/ 09 октября 2011

Я бы хотя бы немного соблазнился использовать встроенные функции C99 для «покрытия» функций libpcap.Если функция libpcap имеет значение unsigned char *libpcap_func(int fd, unsigned char *buffer, size_t buflen), то вы можете написать и использовать:

static inline char *pc_libpcap_func(int fd, char *buffer, size_t buflen)
{
    return (char *)libpcap_func(fd, (unsigned char *)buffer, bufflen);
}

Конечно, это будет заголовок.Префикс pc_ предназначен для «обычного char».Вы можете написать одну из этих функций покрытия для каждой используемой вами функции libpcap (возможно, даже для тех, которые не принимают никаких простых указателей на символы, только для согласованности).

Вы должны написать свой код для вызоваpc_ версии функции.

Поскольку они встроены, они будут такими же эффективными, как макросы, что было бы классическим способом решения проблемы:

#define libpcap_func(fd, buffer, buflen) \
                ((char *)(libpcap_func)(fd, (unsigned char *)(buffer), bufflen)

Этот немного хитрый код основывается на том факте, что когда имя макроса, похожее на функцию, появляется без открывающей скобки в качестве следующего токена, это не вызов этого макроса, а также тот факт, что когда макрос расширяется, его символбольше не подходит для расширения (предотвращение бесконечной рекурсии в препроцессоре; ISO / IEC 9899: 1999 § 6.10.3.4 «Повторное сканирование и дальнейшая замена»).Или вы можете назвать макросы с префиксом pc_, как со встроенными функциями.

0 голосов
/ 09 октября 2011

Сохраняйте беззнаковый символ * и приводите при вызове строковых функций.

Значение со знаком не эквивалентно значению без знака, которое вы можете получить во всех видах беспорядков, игнорируя этот факт.Например, если вы сравните знак со знаком и знак без знака со значением 0xff со целым числом со знаком со значением -1, вы получите разные результаты.

ANSI C (и более поздние стандарты) не определяют, является ли char подписанным или неподписанным по умолчанию, он остается на усмотрение разработчика компилятора, чтобы решить это (это даже упоминается в начале книги K & R).

Тем не менее, я бы оставил все как есть и использовал его там, где это необходимо, только если вы знаете, что это безопасно.Я рассуждаю так: если кому-то еще понадобится работать с вашим кодом, он будет знать о том, что эти данные по какой-то причине не подписаны.Из-за этого они, вероятно, смогут задать тот же вопрос, что и вы, а не предполагать, что его можно рассматривать как строку.Также приведение будет сообщать намерение преобразовать тип.

Мне, вероятно, не нужно говорить вам, что вам следует остерегаться ненулевых оконечных строк, особенно когда имеешь дело с внешним миром.

0 голосов
/ 09 октября 2011

Для меня это похоже на стилистический вопрос, и на вашем месте я бы использовал формат, который будет использоваться большинством функций. Если у вас есть два или три, которые хотят получить char *, я бы разыграл его для тех немногих случаев. Однако, если у вас есть много функций, которые хотят char *, и только немногие, которые используют unsigned char *, тогда я приведу его, когда вернусь libpcap.

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