Когда использовать пустой указатель?

Во-первых, добавьте комментарии в ваши строки документов, используя формат RestructuredText.

Во-вторых, получить сфинкс .

В-третьих, создайте индекс, который использует расширение autodoc .

Затем запустите Sphinx, чтобы получить действительно хорошую документацию.

41
задан Kekoa 22 June 2009 в 05:53
поделиться

11 ответов

Один хороший сценарий использования 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 ++, у меня нет конкретных полезных примеров.

30
ответ дан 27 November 2019 в 00:37
поделиться

Если вы взаимодействуете с кодом C и вам нужно передать объект C ++, но библиотека C будет принимать только общий указатель, тогда, когда вы извлекаете указатель, вам нужно его повторно преобразовать к правильному типу.

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

13
ответ дан 27 November 2019 в 00:37
поделиться

Другой пример таких «дженериков» C, реализованных с помощью void *, - это стандартная функция qsort:

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

Вы можете отсортировать массив любого типа: int, long, double, char * или некоторые указатели на структуры ...

3
ответ дан 27 November 2019 в 00:37
поделиться

ОТЛИЧНЫЙ способ узнать все о 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 и прочитать там весь материал.

3
ответ дан 27 November 2019 в 00:37
поделиться

void указатели должны использоваться каждый раз, когда содержимое блока данных не важно. Например, при копировании данных копируется содержимое области памяти, но формат данных не важен.

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

9
ответ дан 27 November 2019 в 00:37
поделиться

Обычно используется в числовом коде, например, корневая решающая функция C может выглядеть так:

double find_root(double x0, double (*f)(double, void*), void* params)
{
/* stuff */
y = f(x, params);
/* other stuff */
}

params приводится f к некоторой структуре он знает об этом, но find_root не знает.

3
ответ дан 27 November 2019 в 00:37
поделиться

Помимо взаимодействия с C, я обнаружил, что использую указатели void только тогда, когда мне нужно отладить / отследить какой-то код и я хочу узнать адрес определенного указателя.

SomeClass * myInstance;
// ...
std::clog << std::hex << static_cast< void* >(myInstance) << std::endl;

Напечатает что-то вроде

0x42A8C410

И в моем мнение, красиво документирует то, что я пытаюсь сделать (знать адрес указателя, а не что-либо об экземпляре)

2
ответ дан 27 November 2019 в 00:37
поделиться

Указатели на пустоту полезны, когда вы пишете код, который должен работать в нескольких операционных системах и который не должен зависеть от API-интерфейсов базовой платформы.

Например, OS X, Windows и Linux имеют базовую концепцию оконного объекта, но все они очень разные. Итак, у меня есть общий код, который передает их как void *, а затем специфичные для платформы реализации, которые приводят void * к собственному типу (HWND и т. Д.).

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

2
ответ дан 27 November 2019 в 00:37
поделиться

Посмотрите на sqlite3_exec () . Вы запускаете SQL-запрос и хотите каким-то образом обработать результаты (сохранить их в контейнере). Вы вызываете sqlite3_exec () и передаете указатель обратного вызова и указатель void * на любой желаемый объект (включая контейнер). Когда sqlite3_exec () запускается, он вызывает обратный вызов для каждой полученной строки и передает в нее указатель void *, чтобы обратный вызов мог преобразовать указатель и сделать все, что вы хотели.

Важно то, что sqlite3_exec () не заботится о том, что обратный вызов выполняет и какой указатель вы передаете. void * именно для таких указателей.

1
ответ дан 27 November 2019 в 00:37
поделиться

void * на самом деле является C-измом и позволяет C делать некоторые вещи, которые он не мог бы делать иначе.

char * не может переносимо использоваться для что угодно, поскольку разные платформы могут создавать разные типы указателей - char * не обязательно обрабатывается так же (или даже имеет тот же размер), что и void * .

Поэтому, когда тип данных неизвестен в C (или является полиморфным или динамическим), тогда void * позволяет вам сгенерировать правильный базовый тип указателя - тот, который может указывать на что угодно правильно.

В C ++ void * обычно никогда не возникает, кроме как в контексте взаимодействия с устаревшим кодом C в той или иной форме.

2
ответ дан 27 November 2019 в 00:37
поделиться
int (*f) (void);
f =(void*) getprocaddress(dll,"myfunction");

, чтобы компилятор был доволен

-3
ответ дан 27 November 2019 в 00:37
поделиться