Проблема с компиляцией примера K & R - PullRequest
5 голосов
/ 06 марта 2009

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

#define MAXLINES 5000
char *lineptr[MAXLINES];

void qsort1(void *lineptr[], int left, int right, int (*comp)(void *, void *));
int numcmp(char *, char *);

main(int argc, char *argv[]) {
    int numeric = 1;
    /* ... */
    qsort1((void**) lineptr, 0, 100, (int (*)(void*, void*))(numeric ? numcmp : strcmp));
}

void qsort1(void *v[], int left, int right, int (*comp)(void *, void *)) {
    /* ... */
}

int numcmp(char *s1, char *s2) {
    /* ... */
}

Проблема в том, что код не компилируется (я использую компилятор Digital Mars). Я получаю следующую ошибку:

        qsort1((void**) lineptr, 0, nlines - 1, (int (*)(void*, void*))(numeric
? numcmp : strcmp));

                 ^
go.c(19) : Error: need explicit cast to convert
from: int (*C func)(char const *,char const *)
to  : int (*C func)(char *,char *)
--- errorlevel 1

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

РЕДАКТИРОВАТЬ: я должен был упомянуть, что я читаю ANSI-версию книги.

Ответы [ 5 ]

9 голосов
/ 06 марта 2009

Я думаю, что ошибка связана с тем, что старый C еще не знал const: в strcmp было два указателя на неконстантные символы (char *), я думаю (что могло быть причиной того, что он компилировался тогда, но не с вашим компилятором). Однако в настоящее время strcmp занимает char const* (const char* - это то же самое). Измените свой прототип функции на это:

int numcmp(char const*, char const*);
2 голосов
/ 06 марта 2009

Стандартный указатель на функцию, ожидаемый qsort() или bsearch(), имеет прототип:

int comparator(const void *v1, const void *v2);

qsort1(), определенный в коде, ожидает:

int comparator(void *v1, void *v2);

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

Итак, исправления для qsort1():

  1. Введите приведение: (int (*)(void *, void *)) или
  2. Перепишите компараторы:

    int numcmp(void *v1, void *v2)
    {
        char *s1 = v1;
        char *s2 = v2;
        ...
    }
    
    int str_cmp(void *v1, void *v2)  // Note new function name!
    {
        return(strcmp(v1, v2));
    }
    

Очевидно, что вызов qsort1() будет ссылаться на str_cmp вместо strcmp. Авторы стремились избежать промежуточной функции, но запутали (законно) более сложные компиляторы, используемые в настоящее время.

Стандартная версия qsort() потребует несколько квалификаторов const, как в первой версии этого ответа.

2 голосов
/ 06 марта 2009

Это общая проблема:)

Следующая строка указывает qsort ожидать указатель на функцию с двумя параметрами void *. К сожалению, strcmp принимает две неизменяемые строки, поэтому его подпись

int (*comp)(const char*, const char*)

вместо того, что у вас есть:

int (*comp)(void *, void *)

Изменить подпись как qsort1, так и numeric:

qsort1(void *v[], int left, int right, int (*comp)(const void *, const void *))

и

int numcmp(const char*, const char*)
1 голос
/ 06 марта 2009

Обратите внимание, что strcmp принимает два const аргумента, а ваш numcmp - нет. Следовательно, типы двух функций не совпадают, и оператор ? : будет жаловаться.

Выполните одно из:

  1. изменить numcmp, чтобы соответствовать прототипу strcmp в терминах постоянства
  2. нажмите (int (*)(void*, void*)) бросок внутри ? :, например,

    numeric ? (int (*)(void*, void*))numcmp : (int (*)(void*, void*))strcmp
    
0 голосов
/ 06 марта 2009

Прошло немного времени, так как я занимался программированием на чистом C, я не уверен в новом стандарте.

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

перепишите qsort для принятия ** вместо * [], и все будет в порядке.

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