void* или char* для общего представления буфера?

Я разрабатываю класс буфера, целью которого является представление куска памяти.

мой базовый буфер char* (ну,boost::shared_array<char> на самом деле, но это неважно).

Я застрял в решении, какой прототип выбрать для моего конструктора:

должен ли я пойти с:

Buffer(const void* buf, size_t buflen);

или:

Buffer(const char* buf, size_t buflen);

или что-то еще ?

что обычно делается и почему ?

6 ответов


интерфейс API более понятен для пользователя, если буфер имеет тип void*, а строка имеет тип char*. Сравнить функции memcpy и strcpy и определений функций.


для конструктора и других функций API, преимущество void* заключается в том, что он позволяет вызывающему объекту передавать указатель на любой тип без необходимости делать ненужное приведение. Если это имеет смысл для вызывающего абонента, чтобы иметь возможность передать в любом типе, то void* предпочтительнее. Если это действительно имеет смысл только для вызывающего абонента, чтобы иметь возможность передать char*, затем используйте этот тип.


C++17

в C++17 введен std::byte специально для этого.

его определение на самом деле все просто: enum class byte : unsigned char {};.


Я, как правило, используется unsigned char в качестве базовой структуры (не хочу, чтобы signedness испортил мой буфер по какой-то причине). Однако я обычно typedefed это:

// C++11
using byte = unsigned char;

// C++98
typedef unsigned char byte;

а затем обратитесь к нему как byte*, которое хорошо передает смысл, на мой взгляд, лучше, чем любой из них!--5--> или void* по крайней мере.


Я бы предпочел char*, потому что для меня лично он лучше играет с "буфером". void* больше похоже на "указатель на Я не знаю, что". Кроме того, это то, что лежит в основе всего.


Я бы рекомендовал uint8_t, который определен в stdint.h. Это в основном то же самое, что и "typedef unsigned char byte"; что рекомендовали другие, но у него есть преимущество быть частью стандарта C.

Что касается void*, я бы использовал это только для полиморфизма. то есть. Я бы назвал что-то указателем пустоты, если бы еще не знал, на что оно будет указывать. В вашем случае у вас есть массив байтов, поэтому я бы обозначил его как таковой, используя uint8_t* как тип.


предпочитаю unsigned char * или uint8_t * для буферных реализаций, так как void * имеет раздражающее ограничение, что вы не можете выполнить математику указателя на нем. Поэтому, если вы хотите обработать некоторые данные с некоторым смещением от буфера или просто разбить буфер на куски или что-то еще, вы все равно застряли в каком-то другом типе, чтобы сделать математику.

предпочитаю unsigned char * или uint8_t * над равниной char * из-за специальные правила по поводу сглаживания и char *, который имеет потенциал, чтобы серьезно pessimize несколько петель, работающих на вашем буферов.