Совместимы ли char * и const char * при использовании тернарного оператора в C?

Я получил ошибку из следующего кода. Я компилировал с помощью gcc6.3.0.

#include <stdio.h>
#include <string.h>

#define MAXLINES 5000
char *lineptr[MAXLINES];

int readlines(char *lineptr[], int nlines);
void writelines(char *lineptr[], int nlines);

void myqsort(void *lineptr[], int left, int right, 
           int (*comp)(void *, void *));

int numcmp(char *, char *);

int main(int argc, char *argv[])
{
    int nlines;
    int numeric = 0;

    if (argc > 1 && strcmp(argv[1], "-n") == 0)
        numeric = 1;
    if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
        myqsort((void **) lineptr, 0, nlines-1,
            (int (*)(void*, void*))(numeric ? numcmp : strcmp));
        writelines(lineptr, nlines);
        return 0;
    } else {
        printf("input too big to sort\n");
        return 1;
    }
}
warning: pointer type mismatch in conditional expression
    (int (*)(void*, void*))(numeric ? numcmp : strcmp));
                                             ^

Вот прототипы двух функций numcmp и strcmp.

int numcmp(char *, char *);
int strcmp(const char *, const char *);

В этом Почта ответчик сказал, что они несовместимы. А вот n1256 6.5.15 p3 говорит что (с моим жирным шрифтом)

One of the following shall hold for the second and third operands:
— both operands have arithmetic type;
— both operands have the same structure or union type;
— both operands have void type;
— both operands are pointers to qualified or unqualified versions of compatible types;
— one operand is a pointer and the other is a null pointer constant; or
— one operand is a pointer to an object or incomplete type and the other is a pointer to a qualified or unqualified version of void.

Они несовместимы, но соответствуют ограничениям стандарта. Но почему компилятор выдает сообщение об ошибке? Должен ли я конвертировать int numcmp(char *, char *); в int numcmp(const char *, const char *);, чтобы использовать тернарный оператор?

Я не знаю правил для этого конкретного случая и у меня нет подходящего компилятора, но стоит заставить numcmp принимать указатели const char в любом случае, чтобы сделать его а) более полезным и б) лучше передать свое намерение не изменять строки, на которые указывает своими аргументами. Это может сработать, почему бы вам не попробовать?

nanofarad 08.04.2021 07:37

@nanofarad Я решал упражнение из моей книги C, и функция написана в такой форме. Я согласен с вашей идеей, но мне было просто любопытно, почему мой gcc пожаловался на это сообщение.

op ol 08.04.2021 07:40

Ваша логика применима, если бы два операнда были типа char * и const char *. Но вместо этого они относятся к типам int (*)(char *, char *) и int (*)(const char *, const char *), которые являются неквалифицированными указателями на два разных типа.

Nate Eldredge 08.04.2021 07:43

И вы можете прочитать определения в стандарте, чтобы убедиться, что «функция, возвращающая int и принимающая два параметра char *» и «функция, возвращающая int и принимающая два параметра const char *» - несовместимые типы. Все сводится к тому, что const char и char несовместимые типы, потому что они не имеют одинаковой квалификации: 6.7.3 (9).

Nate Eldredge 08.04.2021 07:51
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
45
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

They aren't compatible but meet the standard's constraint.

Я так не думаю.

numcmp относится к типу int (*)(char *, char *), тогда как strcmp относится к int (*)(const char *, const char *). Итак, один - указатель на int (char *, char *), а другой - на int (const char *, const char *). Ни один из типов int (char *, char *) и int (const char *, const char *) не квалифицирован; действительно, тип функции не может быть квалифицирован (6.7.3 (8)). Это будет что-то вроде const function returning int, а функция не может быть const.

Итак, нам осталось спросить, являются ли int (char *, char *) и int (const char *, const char *) совместимыми типами. Это оба типа функций, поэтому мы проверяем 6.7.5.3 (15):

For two function types to be compatible, both shall specify compatible return types.

Хорошо, int и int совместимы, потому что они одного типа (6.2.7 (1)).

Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types.

Хорошо, поэтому нам нужно выяснить, являются ли char * и const char * совместимыми типами. Это типы указателей, поэтому мы проверяем 6.7.5.1 (2).

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

Ни один из этих типов не квалифицирован. (char * const будет квалифицирован как const, а const char * - нет.) Один - указатель на char, а другой - указатель на const char. Итак, нам нужно выяснить, являются ли char и const char совместимыми типами. Последний квалифицирован, поэтому мы проверяем 6.7.3 (9):

For two qualified types to be compatible, both shall have the identically qualified version of a compatible type; the order of type qualifiers within a list of specifiers or qualifiers does not affect the specified type.

Ой. char и char являются совместимыми типами, но char и const char не имеют одинаковой квалификации, поэтому они несовместимы.

Другие вопросы по теме