Во-первых, добавьте комментарии в ваши строки документов, используя формат RestructuredText.
Во-вторых, получить сфинкс .
В-третьих, создайте индекс, который использует расширение autodoc .
Затем запустите Sphinx, чтобы получить действительно хорошую документацию.
Один хороший сценарий использования void *
- это когда вы хотите реализовать какие-либо общие ADT, на случай, если вы просто не знаете, какой тип данных он будет хранить и с которым будет иметь дело. Например, связанный список, подобный следующему:
typedef struct node_t node;
struct
{
void* data;
node* prev, next;
} node_t;
typedef struct list_t list;
typedef void* (func)(void*) cpy_func;
typedef void (func)(void*) del_func;
struct
{
node* head, tail, curr;
cpy_func copy;
del_func delete;
} list_t;
initializeLinkedList(cpy_func cpy, del_func del);
//here you keep going defining an API
Здесь, например, вы передадите указатели функций инициализации другим функциям, которые будут способны копировать ваш тип данных в ваш список и впоследствии освобождать его. Таким образом, используя void *
, вы делаете свой список более общим.
Я думаю, что void *
остался в C ++ только из-за обратной совместимости, поскольку в C ++ у вас есть более безопасные и сложные способы для достижения того же результата, что и шаблоны, функторы и т. д., и вам не нужно использовать malloc при программировании на C ++.
Что касается C ++, у меня нет конкретных полезных примеров.
Если вы взаимодействуете с кодом C и вам нужно передать объект C ++, но библиотека C будет принимать только общий указатель, тогда, когда вы извлекаете указатель, вам нужно его повторно преобразовать к правильному типу.
Пустые указатели, вероятно, не следует использовать очень часто, но они могут помочь, когда вы пытаетесь использовать библиотечную функцию, которая работает с произвольными указателями и на самом деле не заботится о том, какие данные представлены это воспоминание.
Другой пример таких «дженериков» C, реализованных с помощью void *, - это стандартная функция qsort:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
Вы можете отсортировать массив любого типа: int, long, double, char * или некоторые указатели на структуры ...
ОТЛИЧНЫЙ способ узнать все о void * и других темах C - это посмотреть первую половину фантастических Стэнфордских «Парадигм программирования» на iTunes-U. Это действительно фантастически объясняет void * (C generics) и указатели в целом! Это определенно помогло мне лучше изучить C ...
Одно из самых больших применений - использование void *, если вы хотите иметь возможность принимать различные типы данных в функции. (вот пример: http://142.132.30.225/programming/node87.html )
Вот еще один пример того, для чего вы можете их использовать:
int i;
char c;
void *the_data;
i = 6;
c = 'a';
the_data = &i;
printf("the_data points to the integer value %d\n", *(int*) the_data);
the_data = &c;
printf("the_data now points to the character %c\n", *(char*) the_data);
Если вы не хотите посмотрите бесплатные уроки Стэнфорда, я бы порекомендовал поискать в Google void pointer и прочитать там весь материал.
void
указатели должны использоваться каждый раз, когда содержимое блока данных не важно. Например, при копировании данных копируется содержимое области памяти, но формат данных не важен.
Для функций, которые работают с блоками памяти без необходимости понимания содержимого, с помощью указателей void
поясняется дизайн для пользователей, чтобы они знали, что функция не заботится ни о каком формате данных.
Часто функции кодируются так, чтобы принимать char *
для обработки блоков памяти, когда функция фактически не зависит от содержимого.
Обычно используется в числовом коде, например, корневая решающая функция C может выглядеть так:
double find_root(double x0, double (*f)(double, void*), void* params)
{
/* stuff */
y = f(x, params);
/* other stuff */
}
params
приводится f
к некоторой структуре он знает об этом, но find_root
не знает.
Помимо взаимодействия с C, я обнаружил, что использую указатели void только тогда, когда мне нужно отладить / отследить какой-то код и я хочу узнать адрес определенного указателя.
SomeClass * myInstance;
// ...
std::clog << std::hex << static_cast< void* >(myInstance) << std::endl;
Напечатает что-то вроде
0x42A8C410
И в моем мнение, красиво документирует то, что я пытаюсь сделать (знать адрес указателя, а не что-либо об экземпляре)
Указатели на пустоту полезны, когда вы пишете код, который должен работать в нескольких операционных системах и который не должен зависеть от API-интерфейсов базовой платформы.
Например, OS X, Windows и Linux имеют базовую концепцию оконного объекта, но все они очень разные. Итак, у меня есть общий код, который передает их как void *, а затем специфичные для платформы реализации, которые приводят void * к собственному типу (HWND и т. Д.).
Но, да, как говорили другие в этом потоке, это такого рода вещей, безусловно, следует избегать, за исключением случаев, когда это необходимо.
Посмотрите на sqlite3_exec () . Вы запускаете SQL-запрос и хотите каким-то образом обработать результаты (сохранить их в контейнере). Вы вызываете sqlite3_exec () и передаете указатель обратного вызова и указатель void * на любой желаемый объект (включая контейнер). Когда sqlite3_exec () запускается, он вызывает обратный вызов для каждой полученной строки и передает в нее указатель void *, чтобы обратный вызов мог преобразовать указатель и сделать все, что вы хотели.
Важно то, что sqlite3_exec () не заботится о том, что обратный вызов выполняет и какой указатель вы передаете. void * именно для таких указателей.
void *
на самом деле является C-измом и позволяет C делать некоторые вещи, которые он не мог бы делать иначе.
char *
не может переносимо использоваться для что угодно, поскольку разные платформы могут создавать разные типы указателей - char *
не обязательно обрабатывается так же (или даже имеет тот же размер), что и void *
.
Поэтому, когда тип данных неизвестен в C (или является полиморфным или динамическим), тогда void *
позволяет вам сгенерировать правильный базовый тип указателя - тот, который может указывать на что угодно правильно.
В C ++ void *
обычно никогда не возникает, кроме как в контексте взаимодействия с устаревшим кодом C в той или иной форме.
int (*f) (void);
f =(void*) getprocaddress(dll,"myfunction");
, чтобы компилятор был доволен