Указатели на функции в C - адрес оператора "ненужный" - PullRequest
7 голосов
/ 03 ноября 2008

Используя qsort в C, мы передаем функцию сравнения, например,

int cmp(const void*, const void*);

прототип qsort ожидает int (*) (const void *, const void *), поэтому мы вызываем:

qsort(..., cmp);

но в равной степени можно звонить:

qsort(..., &cmp);

и это то, что мы должны были бы сделать, если бы передали статическую функцию-член в C ++. Kernighan & Ritchie (2nd Edition, 5.11 «Pointers To Functions» p119) утверждает, что «поскольку [cmp], как известно, является функцией, оператор & не является необходимым, так же как он не нужен перед именем массива. «

Кто-нибудь еще чувствует себя немного неловко с этим (особенно в отношении безопасности типов)?

Ответы [ 6 ]

8 голосов
/ 03 ноября 2008

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

int main()
{
   int integer = 0xFFFFFF; 
   void (*functionPointer)() = (void(*)())integer; 

   functionPointer(); 

   return 0; 
}

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

5 голосов
/ 05 ноября 2008

Ответ таков: передача функции по значению дает указатель на функцию, так же как передача массива по значению дает указатель на ее первый элемент. говорят, что массив и функция «распадаются». Есть только несколько случаев, когда этот распад не происходит. например, sizeof (массив) возвращает размер массива, а не указатель на его первый элемент. sizeof (функция) недопустима (функции не являются объектами), вы должны сделать sizeof (& function). Другие случаи обязательны для ссылок:

void baz();

void foo(void (&bar)()) {
    bar();
}

// doesnt work, since a reference to a function is requested. 
// you have to pass 'bar' itself, without taking its address 
// explicitely.
foo(&baz);  

Это, кстати, все, что вы можете сделать

template<typename T, int N>
void ByRef(T (&foo)[N]) { 
    ...
}

, так как массив еще не разрушается при рассмотрении опорных параметров.

4 голосов
/ 03 ноября 2008

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

Другими словами, нет разумного определения для манипулирования «значением» функции.

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

В любом случае, C предшествует как C ++, так и его собственной стандартизации - у оригинального K & R C даже не было прототипов, и ANSI должен был убедиться, что их стандартизация не сломала существующий код в максимально возможной степени.

3 голосов
/ 03 ноября 2008

Это детали синтаксиса. Если вам не нравится не использовать & для обозначения указателя функции, всегда используйте его. Если вам нравится сохранять лишние нажатия клавиш и не так явно выражать свою кодировку, воспользуйтесь этим.

Что касается безопасности типов, я не понимаю, как это имеет значение. Компилятору дается функция в качестве аргумента, и он может определить, какая сигнатура функции целиком из названия. Тот факт, что вы не вызываете его (с синтаксисом ()), дает полное представление о том, что компилятору нужно, чтобы вы указали указатель на функцию в этом месте. Символ & - это просто синтаксическая хитрость, указывающая людям, что они смотрят на указатель какого-то описания.

Если вы используете C ++, тогда я бы посоветовал рассматривать буст-функторы как более приятный способ передачи функций в любом случае. Эти симпатичные сущности допускают унифицированный и довольно понятный синтаксис для всех функций в C ++:)

1 голос
/ 04 ноября 2008

Обратите внимание, что то же самое относится к указателям на функции разыменования (то есть вызова); вам не нужно

(*funcptr)(arg1, arg2);

в

funcptr(arg1, arg2);

будет достаточно.

1 голос
/ 03 ноября 2008

Это не столько чувство дискомфорта, сколько отвращение к допустимым, но пока противоречивым вариантам синтаксиса. Либо cmp является указателем, и его следует рассматривать как единое целое, либо это какой-то другой тип, который, IMHO, синтаксически вводит в заблуждение.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...