Чи є void * function () вказівник на функцію або функція, що повертає порожнечу *?


26

Мене плутає сенс void *function().
Це вказівник на функцію чи функція, що повертається void*? Я завжди використовував це в структурах даних як рекурсивну функцію, що повертає вказівник, але коли я побачив код у багатопотоковому читанні ( pthread), є однакове оголошення функції. Тепер я розгублений, в чому різниця між ними.


5
@goodvibration C була створена без формату (і C ++ "успадкував" це). Навіть void*function();синтаксично правильно. Наприклад, для Python вони обрали інше рішення - формат є частиною синтаксису. ІМХО, обидва способи мають свої плюси та мінуси.
Scheff

3
@goodvibration тим більше ви намагаєтеся захистити програміста від того, що вони хочуть, тим більше ви отримуєте щось на кшталт java;)
idclev 463035818

2
@goodvibration Менше варіантів, менша гнучкість. І, будь ласка, майте на увазі, що це робили десятиліття тому. Після цього легко поскаржитися ... ;-)
Scheff

2
У мові С void *function()- це функція, що приймає довільну кількість аргументів і повертає значення, яке при відхиленні від типу недійсне . У C ++ void* function()- це функція, яка не бере аргументів і повертає значення покажчика на недійсність . Ви повинні вирішити, про яку мову ви питаєте.
Стівен М. Уебб

1
@ StephenM.Webb Ви не можетеvoid * скинути a . Зрештою, навіть якби ви могли, що б ви зробили з void?
Фабіо каже:

Відповіді:


38

Функція має тип повернення void *.

void *function();

Тому я завжди вважаю за краще в таких випадках відокремлювати символ *від назви функції типу

void * function();

І як Jarod42вказувалося в коментарі, ви можете переписати декларацію функції в C ++, використовуючи тип віддаленого повернення типу

auto function() -> void *;

Якщо ви хочете оголосити покажчик на функцію, то слід написати

void ( *function )();

Або

void * ( *function )();

Або вказівник на функцію, який повертає покажчик на функцію

void * ( *( *function )() )();

2
Ось чому я вважаю за краще писати void* function();. Це не те, що спокушає ... ;-) (Правка сталася саме під час написання цього запису.)
Scheff

у коді я оголошую void * reader();потім pthread_create(&thread1,null,reader,reader_arg)замістьpthread_create(&thread1,null,&reader,reader_arg)
user9515151

1
@Scheff: Або навіть auto function() -> void*(C ++). :)
Jarod42

3
Або вказівник на функцію, який повертає вказівник на функцію Ось що typedefдля ... ;-)
Ендрю Генле

1
@AndrewHenle З typedef у нас немає проблем. Проблема виникає, коли декларації використовуються без typedef або декларації з псевдонімом. :)
Влад з Москви

7

Щоразу, коли я не впевнений у проблемах синтаксису С, я люблю використовувати утиліту cdecl ( онлайн-версія ) для тлумачення мене. Він перекладається між синтаксисом С та англійською мовою.

Наприклад, я ввожу ваш приклад, void *foo()і він повернувся

оголосити foo як функцію, що повертає вказівник на недійсний

Щоб побачити, як виглядатиме інший синтаксис, я ввів declare foo as pointer to function returning voidі він повернувся

пустота (* foo) ()

Це стає особливо корисним, коли у вас є декілька рівнів набору текстів, зірок або дужок в одному виразі.


2

Це функція, що повертає покажчик на void.

Подумайте про свою декларацію таким чином:

void *(function());

Це буде функцією, що повертається void(або нічого):

void (*function2)();

Подумайте над наведеною декларацією таким чином:

void ((*function2)());

Набагато простішим способом їх написання є використання typedefs:

typedef void *function_returning_void_pointer();
typedef void function_returning_nothing();

function_returning_void_pointer function;
function_returning_nothing *function2;

Це, як правило, усуває плутанину навколо покажчиків функцій і читається набагато простіше.


0

Декларації в C / C ++ читаються з ідентифікатора назовні, після пріоритету оператора .

Швидкий погляд на таблицю пріоритетності оператора C / C ++ у Вікіпедії виявляє, що оператор виклику функції ()має більш високий пріоритет, ніж оператор непрямості *. Отже, ваші декларації функції звучать так:

  • Почніть з ідентифікатора: functionє

  • function() функція, яка не бере аргументів

  • void* function()і повертає a void*.

Цей загальний принцип також дотримується при оголошенні масиву ( []також має більшу перевагу, ніж *) та їх комбінаціях. Тому

int *(*arr[42])();

читається як

  • arr є
  • arr[42] масив з 42 елементів, які є
  • *arr[42] покажчики на
  • (*arr[42])() функції, які не беруть аргументів і
  • int *(*arr[42])()повернути int*.

Потрібно трохи звикнути до цього, але, зрозумівши принцип, легко прочитати ці декларації однозначно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.