Является ли void * function () указателем на функцию или функцию, возвращающую void *?

26

Я запутался в значении void *function().
Это указатель на функцию или возвращаемую функцию void*? Я всегда использовал его в структурах данных как рекурсивную функцию, возвращающую указатель, но когда я увидел код в многопоточности ( pthread), было одно и то же объявление функции. Теперь я запутался в чем разница между ними.

user9515151
источник
5
@goodvibration C был сделан безформатным (и C ++ «унаследовал» это). Даже void*function();синтаксически правильно. Например, для Python они выбрали другое решение - формат является частью синтаксиса. ИМХО, оба способа имеют свои плюсы и минусы.
Scheff
3
@goodvibration: чем больше вы пытаетесь защитить программиста от того, что он хочет, тем больше вы получаете что-то вроде java;)
idclev 463035818
2
@goodvibration Меньше вариантов, меньше гибкости. И, пожалуйста, имейте в виду, что это было десятилетия назад, когда они это сделали. После этого легко жаловаться ... ;-)
Scheff
2
В языке C void *function()это функция, принимающая произвольное количество аргументов и возвращающая значение, которое при разыменовании имеет тип void . В C ++ void* function()это функция, не имеющая аргументов и возвращающая значение указателя на пустоту . Вы должны решить, на каком языке вы спрашиваете.
Стивен М. Уэбб
1
@ StephenM.Webb Вы не можете разыменовать avoid * . В конце концов, даже если бы вы могли, что бы вы сделали с 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
@ Шефф: Или даже auto function() -> void*(C ++). :)
Jarod42
3
Или указатель на функцию, которая возвращает указатель на функцию Вот для чего typedef... ;-)
Эндрю
1
@AndrewHenle С typedef у нас нет проблем. Проблема возникает, когда объявления используются без typedef или объявления псевдонимов. :)
Влад из Москвы
7

Всякий раз, когда я не уверен в проблемах с синтаксисом языка Си, мне нравится использовать утилиту cdecl ( онлайн-версия ) для интерпретации для меня. Он переводит между C синтаксис и английский.

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

объявить foo как функцию, возвращающую указатель на void

Чтобы увидеть, как будет выглядеть другой синтаксис, я ввел declare foo as pointer to function returning voidи он вернулся

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()и возвращает void*.

Этот общий принцип также применим к объявлениям массивов ( []также имеет более высокий приоритет, чем *) и комбинациям этих двух. Так

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

читается как

  • arr является
  • arr[42] массив из 42 элементов, которые
  • *arr[42] указатели на
  • (*arr[42])() функции, которые не принимают аргументов и
  • int *(*arr[42])()вернуть int*.

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

cmaster - восстановить монику
источник