Ответ 1
Интерфейс API более понятен для пользователя, если буфер имеет тип void *, а строка имеет тип char *. Сравните определения функций memcpy и strcpy.
Я разрабатываю класс Buffer, целью которого является представление фрагмента памяти.
Мой базовый буфер - это char*
(ну, a boost::shared_array<char>
на самом деле, но это не имеет значения).
Я застрял в решении, какой прототип выбрать для моего конструктора:
Должен ли я идти с:
Buffer(const void* buf, size_t buflen);
Или с помощью:
Buffer(const char* buf, size_t buflen);
Или что-то еще?
Что обычно делается и почему?
Интерфейс API более понятен для пользователя, если буфер имеет тип void *, а строка имеет тип char *. Сравните определения функций memcpy и strcpy.
Для конструктора и других функций API преимущество void*
заключается в том, что он позволяет вызывающему передать указатель на любой тип без необходимости делать ненужный приведение. Если имеет смысл, чтобы вызывающий мог передать любой тип, тогда void*
является предпочтительным. Если действительно действительно имеет смысл, чтобы вызывающий мог пройти через char*
, тогда используйте этот тип.
Я обычно использую unsigned char
как базовую структуру (не хочу, чтобы подписанность была испорчена для моего буфера, потому что я знаю, какую причину). Однако я обычно набираю текст:
typedef unsigned char byte;
И затем назовите его как byte*
, который аккуратно передает значение, на мой взгляд, лучше, чем char*
или void*
по крайней мере.
Я бы предпочел char*
, потому что для меня лично он лучше играет с "буфером". void*
больше похоже на "указатель на то, что я не знаю, что". Кроме того, это то, чем вы являетесь, в любом случае.
Я бы рекомендовал uint8_t, который определен в stdint.h. Это в основном то же самое, что и "typedef unsigned char byte;" что другие рекомендуют, но он имеет то преимущество, что является частью стандарта C.
Что касается void *, я бы использовал его только для полиморфизма. то есть. Я бы назвал только указатель на пустоту, если бы еще не знал, на что он будет ссылаться. В вашем случае у вас есть массив байтов, поэтому я бы назвал его как таковой, используя uint8_t * в качестве типа.
Я предпочитаю unsigned char *
или uint8_t *
для реализаций буфера, поскольку void *
имеет раздражающее ограничение, которое вы не можете выполнить на нем. Поэтому, если вы хотите обрабатывать некоторые данные с некоторым смещением от буфера или просто разбивать свой буфер на куски или что-то еще, вы все равно придерживаетесь какого-либо другого типа, чтобы выполнить математику.
Я предпочитаю unsigned char *
или uint8_t *
поверх plain char *
из-за специальных правил относительно сглаживания и char *
, что может серьезно пессимизировать некоторые петли работают на ваших буферах.