4

Последний параметр этой строки в main() делает меня потерялСмешение линия в K & R 5,11 указатели на функции C

// declaration 
void qsort(char *linep[], int left, int right, int (*compare)(void *, void*); 

// use 
main(){ 
    qsort((void**) lineptr, 0, nlines-1, (int (*)(void*,void*))(numeric ? 
    numcmp : strcmp)); 
} 

Я понимаю, тройной оператор, но скажем числовой == 0, то что это значит?

(int (*)(void *, void*))strcmp; 

Не соответствуют ли типы данных функциональным параметрам?

int strcmp(const char*, const char*); 
void qsort(, , , int(*)(void*)(void*); 

Могу ли я называть указатель на функцию?

+0

Остерегайтесь K & R, это опасная книга, которая учит множеству неправильной или плохой практики программирования. Этот пример 5.11 является одним из таких примеров, поскольку код основан на неопределенном поведении. Кроме того, как мы видим, код K & R также является нечитаемым беспорядком. – Lundin

+0

Я всегда пылаю для публикации кода K & R где-то, спасибо за это! – Pruzo

+0

Ваш вопрос в порядке, это проблема K & R, а не ваш вопрос.Очень разумно спрашивать об этом, потому что на самом деле логично предположить, что создатель языка знал бы язык лучше, чем кто-либо другой. Увы, это было верно только до 1989 года. Попытка обновить книгу K & R до предположительно второго стандарта ISO C была неаккуратной; осталось много стандартного кода. – Lundin

ответ

4

В вашем коде, используя актерский

(int (*)(void *, void*))strcmp; 

означает, strcmp() является функцией указателя, который принимает два аргумента void * и возвращает int.

Обычно для указателей на функции, литье очень плохая идея, так как цитаты из C11, глава §6.3.2.3

[...] If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.

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

+0

, так что я сделал то, что я присваивал int strcmp (char *, char *) значение int strcmp (void *, void *) и передал его как аргумент? – Pruzo

+0

@Pruzo да, правый. –

+0

В этом случае литье также не важно, не так ли? Просто вызов 'qsort' с последним параметром как' strcmp' должен работать из-за неявного перевода из 'const char *' в 'void *'. –

0

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

Здесь также нет: на вашей стандартной архитектуре (солнечные рабочие станции, ПК с Linux, малиновый PI) указатели аргументов на разные типы данных представлены одинаково, так что никакого ущерба не ожидается. Функция будет считывать значение 4 или 8 байтов из стека и интерпретировать память, указанную как данные ожидаемого типа (который должен иметь хотя бы, например, не использовать функцию сравнения с плавающей точкой в ​​строках, она может вызывать, потому что произвольный бит шаблоны могут быть NaN и т. д.).

Я хотел предупредить вас о том, что сегодняшняя стандартная библиотека qsort имеет другую сигнатуру функции (и семантическую), чем K & Пример R. Сегодняшний qsort получает указатель на начало вектора элементов и вызывает функцию сравнения с указателями на элементы в массиве; в случае массива указателей строк аргументы указатели на указатели, которые не подходят для strcmp(). Аргументы должны быть разыменованы в первую очередь. linux man page for qsort имеет пример для обертки strcmp, которая делает именно это. (Веб-экспорт веб-страницы выглядит несколько искаженным, но все еще доступен для чтения.)

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

  • Нет связанных вопросов^_^