В моих программах на C мне часто нужен способ сделать строковое представление моих ADT. Даже если мне не нужно выводить строку на экран каким-либо образом, очень неплохо иметь такой метод для отладки. Так что такая функция часто появляется.
char * mytype_to_string( const mytype_t *t );
На самом деле я понимаю, что у меня есть (по крайней мере) три варианта обработки памяти для возвращаемой строки.
Альтернатива 1: сохранение возвращаемой строки в массиве статических символов в функции. Мне не нужно много думать, за исключением того, что строка перезаписывается при каждом вызове. Что может быть проблемой в некоторых случаях.
Альтернатива 2: выделите строку в куче с помощью malloc внутри функции. Действительно аккуратный, так как мне не нужно думать о размере буфера или перезаписи. Тем не менее, я должен помнить free () строку после завершения, а затем мне также нужно назначить временную переменную, чтобы я мог освободить. и тогда выделение кучи действительно намного медленнее, чем выделение стека, поэтому будьте узким местом, если это повторяется в цикле.
Альтернатива 3: передать указатель на буфер и позволить вызывающей стороне выделить этот буфер. Подобно:
char * mytype_to_string( const mytype_t *mt, char *buf, size_t buflen );
Это приносит больше усилий звонящему. Я также заметил, что эта альтернатива дает мне другой вариант порядка аргументов. Какой аргумент я должен иметь первым и последним? (на самом деле шесть возможностей)
Итак, что я должен предпочесть? Есть почему? Есть ли какой-то неписаный стандарт среди разработчиков C?
источник
sysctlbyname
в OS X и iOSОтветы:
Методы, которые я видел больше всего, это 2 и 3.
Пользовательский буфер довольно прост в использовании:
Хотя большинство реализаций будет возвращать количество используемого буфера.
Вариант 2 будет медленнее и опасен при использовании динамически связанных библиотек, где они могут использовать разные среды выполнения (и разные кучи). Таким образом, вы не можете освободить то, что было размещено в другой библиотеке. Это тогда требует
free_string(char*)
функции, чтобы иметь дело с этим.источник
printf("MyType: %s\n", mytype_to_string( mt, buf, sizeof(buf));
и, следовательно, я не буду возвращать используемую длину, а указатель на строку. Динамический комментарий библиотеки действительно важен.sizeof(buffer) - 1
должно удовлетворять\0
терминатора?snprintf
.Дополнительная идея дизайна для # 3
По возможности также
mytype
укажите максимальный размер, необходимый для того же файла .h, что иmytype_to_string()
.Теперь пользователь может кодировать соответственно.
порядок
Размер массивов, когда он первый, позволяет использовать типы VLA.
Не так важно с одним измерением, но полезно с 2 или более.
Я вспоминаю, что чтение следующего размера является предпочтительной идиомой в следующем C. Нужно найти эту ссылку ....
источник
В дополнение к отличному ответу @ ratchetfreak, я хотел бы отметить, что альтернатива № 3 следует той же парадигме / шаблону, что и стандартные функции библиотеки C.
Например,
strncpy
.Следование той же парадигме поможет снизить когнитивную нагрузку для новых разработчиков (или даже для вашего будущего Я), когда им нужно использовать вашу функцию.
Единственная разница с тем, что у вас есть в посте, состоит в том, что
destination
аргумент в библиотеках C, как правило, указывается первым в списке аргументов. Так:источник
Помимо того, что то, что вы предлагаете сделать, является неприятным запахом кода, альтернатива 3 звучит лучше для меня. Я также думаю, как @ gnasher729, что вы используете не тот язык.
источник
Если честно, вы можете переключиться на другой язык, где возврат строки не является сложной, трудоемкой и подверженной ошибкам операцией.
Вы можете рассмотреть C ++ или Objective-C, где вы можете оставить 99% своего кода без изменений.
источник