2015-09-25 4 views
-1

Я пытаюсь узнать о указателях void и функциях, имеющих typedef (в C). Я не могу понять концепцию.Понимание указателей void и функций указателя typedef

У меня есть этот простой код:

#include <stdio.h> 

typedef int (*CompareFunc)(void*, void*); 

int compareints(void *a, void *b) 
{ 
    return a-b; 
} 

int comparedbls(void *a, void *b) 
{ 
    return a-b; 
} 

int main() 
{ 
    int a = 1, b = 1; 

    int* ptrA = &a; 
    int* ptrB = &b; 

    CompareFunc test = compareints; 
    printf("%d\n", test(ptrA, ptrB)); 


    return 0; 
} 

Выход здесь "-4". Я не понимаю, почему. Я знаю, что это какая-то кастинг, которую я не делаю, потому что чувствую, что я вычитаю адреса. Я бы напечатал значения void *a и void *b с printf("%d", a), чтобы узнать, какие значения у них есть, но он говорит, что это невозможно, потому что a является указателем на пустоту.

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

Любая помощь будет оценена по достоинству. Спасибо!

+1

Используйте '% p' печатать' 'недействительные * с. Ваш вывод '-4' неудивительный, и вы поймете, почему, как только вы печатаете адреса. Вы используете указатели функций, чтобы вы могли хранить или передавать указатели на функции или обменяться функциями с одной и той же сигнатурой (например, см. Stdlib ['qsort()'] (http: // man7.org/linux/man-pages/man3/qsort.3.html) для примера, где они полезны) –

+0

Спасибо! Это подтвердило, что я вычитал адреса. Никогда не знал о '% p', очень удобно. –

+2

Вы можете найти [Как отсортировать массив структур в C] (https://stackoverflow.com/questions/8721189) и ['qsort()' function - пытаться использовать компаратор) (https: // stackoverflow. com/вопросы/10405786 /) полезно. –

ответ

2

compareints() возвращает разницу между двумя указателями, было ли это вашим намерением или нет. Если нет, то вы можете попробовать это:

int compareints(void *a, void *b) 
{ 
    return *(int *)a - *(int *)b; 
} 

и это:

double comparedbls(void *a, void *b) 
{ 
    return *(double *)a - *(double *)b; 
} 

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

с функцией CompareFunc, должен ли я заставить новую переменную указывать на каждую функцию, которую я хочу?

№ Указатель функции может указывать на любую функцию с той же сигнатурой, что и указатель.

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

Что касается литья, любой тип указателя может быть неявно преобразован в void * и наоборот. Это делается, когда вы вызываете compareints(). При вычитании двух указателей одного типа возвращается значение типа ptrdiff_t, которое затем неявно преобразуется в int при возврате из compareints().


+0

Я вижу, так что я могу продолжать переопределять тест на другие функции, имеющие один и тот же заголовок? Спасибо за объяснение! –

+1

@Maru. Правильно, вы можете назначить адрес любой функции, которая принимает те же аргументы и возвращает то же значение, что и указатель функции. – owacoder

+0

Можете ли вы также ответить на вопрос о кастинге, который я спросил ниже? В случае, если ameyCU не отвечает. –

1
int compareints(void *a, void *b) 
{ 
    return a-b; 
} 

Это возвращает разницу между двумя pointers a and b .Что значение, которое вы получаете, однако, определяется реализацией.

Чтобы получить разницу между их значениями вы можете сделать это -

int compareints(void *a, void *b) 
{ 
    return *(int *)a-*(int *)b; 
} 
+0

Можете ли вы объяснить кастинг? Из того, что я вижу, вы бросаете указатели void на целые указатели, а затем разыгрываете? –

+1

@Maru It.s, потому что вы не можете разыменовать 'void *'. Это приведет к ошибке. Поскольку компилятор не имеет размер объекта, на который указывает этот указатель. Для этого мы используем cast. – ameyCU

+1

@Maru для вычитания целых чисел, вместо указателей на них, вам нужно сначала разыменовать указатели ... но вы не должны пытаться разыменовать 'void *' (потому что он может указывать на что-либо ...), поэтому вместо этого это то, что вы знаете, это в первую очередь. –

Смежные вопросы