Вопрос об указателе функции в C

Вы можете использовать flexbox для этого. Для демонстрации я добавил прозрачность к эмодзи, чтобы показать его центральное положение. На вершине CSS находится custom property, который вы можете изменить, чтобы протестировать разные размеры.

https://jsfiddle.net/uvf2h0sj/

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

display: flex;
justify-content: center;
align-items: center;

:root {
  --size: 100px;
}

body {
  display: flex;
  height: 100vh;
  padding: 0;
  margin: 0;
  justify-content: center;
  align-items: center;
}

div.emoji-container {
  width: 50px;
  height: 50px;
  background-color: red;
  display: flex;
  justify-content: center;
  align-items: center;
}

div.emoji {
  font-size: var(--size);
  line-height: var(--size);
  width: var(--size);
  height: var(--size);
  opacity: 0.5;
  display: flex;
  justify-content: center;
  align-items: center;
}
🏠

6
задан Agnel Kurian 16 April 2009 в 15:11
поделиться

9 ответов

То, что здесь происходит, действительно является актерским составом. Давайте на секунду проигнорируем троичный и притворимся, что numcmp всегда используется. Для целей этого вопроса функции могут выступать в качестве указателей на функции в C. Поэтому, если вы посмотрите на тип числового значения, то на самом деле это

(int (*)(int*,int*))

. Для того, чтобы это правильно использовалось в qsort, у него должны быть параметры void. Поскольку все типы здесь имеют одинаковый размер по отношению к параметрам и возвращаемым типам, можно заменить на другой. Все, что нужно, это приведение, чтобы сделать компилятор счастливым.

(int (*)(void*,void*))(numcmp )
4
ответ дан 8 December 2019 в 05:23
поделиться

Вы пропустили трюк - часть

(numeric ? numcmp : strcmp)

использует тернарный оператор для выборакакой функции вызывается внутри qsort. Если данные числовые, то используется numcmp. Если нет, то используется strcmp. Более читабельная реализация выглядела бы так:

int (*comparison_function)(void*,void*) = 
    (int (*)(void*,void*))(numeric ? numcmp : strcmp);
qsort((void**) lineptr, 0, nlines-1, comparison_function);
5
ответ дан 8 December 2019 в 05:23
поделиться

Я бы, наверное, прочитал это так:

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

PFNCMP comparison_function;

if (numeric)
{
    comparison_function =  numcmp;
}
else
{
    comparison_function = strcmp;
}

qsort((void**) lineptr, 0, nlines-1, comparison_function);

Пример в вопросе имеет явный случай.

1
ответ дан 8 December 2019 в 05:23
поделиться

Кто бы ни написал этот фрагмент кода, он пытался быть слишком умным . По его мнению, он, вероятно, думает, что он хороший программист, делая умную «однострочку». На самом деле, он делает код, который будет менее читабельным и с которым трудно работать в долгосрочной перспективе и должен быть переписан в более очевидной форме, похожей на код Харпера Шелби.

Помните пословицу Брайана Керниган:

Отладка вдвое сложнее, чем запись код в первую очередь. Поэтому, если вы напишите код как умно, насколько это возможно, вы, по определение, недостаточно умное для отладки Это.


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

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

3
ответ дан 8 December 2019 в 05:23
поделиться

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

0
ответ дан 8 December 2019 в 05:23
поделиться

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

4
ответ дан 8 December 2019 в 05:23
поделиться

Как уже указывали другие, для

(int (*)(void*,void*))(numeric ? numcmp : strcmp)

следующим является приведение типа

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

и выражение

(numeric ? numcmp : strcmp)

Объявления на C могут быть довольно сложными для чтения, но их можно изучить. Метод состоит в том, чтобы начать с внутренней части и затем пройти один шаг вправо, затем один шаг влево, продолжая вправо, влево, вправо, влево и т. Д., Пока не закончится. Вы не пересекаете скобки, пока все внутри не будет оценено. Например, для приведенного выше типа (*) указывает, что это указатель. Указатель был единственным в скобках, поэтому мы оцениваем его справа. (void *, void *) указывает, что это указатель на функцию с двумя аргументами указателя. Наконец, int указывает тип возвращаемого значения функции. Обновление: две более подробные статьи: Правило по часовой стрелке / спираль и Чтение деклараций C: Руководство для мистифицированных .

Однако, хорошая новость заключается в том, что, хотя вышеизложенное чрезвычайно полезно знать, что есть чрезвычайно простой способ обмануть : программа cdecl может конвертировать из C в английское описание и наоборот:

cdecl> explain (int (*)(void*,void*))
cast unknown_name into pointer to function (pointer to void, pointer to void) returning int
cdecl> declare my_var as array 5 of pointer to int
int *my_var[5]
cdecl>

Упражнение: какая переменная i ?

int *(*(*i)[])(int *)

Ответьте в rot13 , если на вашем компьютере не установлен cdecl (но вам действительно следует!):

pqrpy> rkcynva vag *(*(*v)[])(vag *)
qrpyner v nf cbvagre gb neenl bs cbvagre gb shapgvba (cbvagre gb vag) ergheavat cbvagre gb vag
pqrpy>
3
ответ дан 8 December 2019 в 05:23
поделиться

Обратите внимание, что стандартное определение qsort () включает в себя const :

void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));

Обратите внимание, что для компаратора строк даются два значения ' char ** ', а не значения char * '.

Я пишу свои компараторы, так что в преобразованиях нет необходимости вызывающий код:

#include <stdlib.h>    /* qsort() */
#include <string.h>    /* strcmp() */

int num_cmp(const void *v1, const void *v2)
{
    int i1 = *(const int *)v1;
    int i2 = *(const int *)v2;
    if (i1 < i2)
        return -1;
    else if (i1 > i2)
        return +1;
    else
        return 0;
}

int str_cmp(const void *v1, const void *v2)
{
    const char *s1 = *(const char **)v1;
    const char *s2 = *(const char **)v2;
    return(strcmp(s1, s2));
}

Заставлять людей писать в коде с использованием ваших функций ужасно. Не.

Две написанные мной функции соответствуют прототипу функции, требуемому стандартом qsort () . Имя функции, за которым не следуют круглые скобки, эквивалентно указателю на функцию.

В более старом коде или коде, написанном теми, кто воспитывался на старых компиляторах, указатели на функции используются с помощью запись:

result = (*pointer_to_function)(arg1, arg2, ...);

В современном стиле написано:

3
ответ дан 8 December 2019 в 05:23
поделиться

Оба numcmp и strcmp являются указателями на функции, которые принимают два char * в качестве параметров и возвращает int . Подпрограмма qsort ожидает указатель на функцию, которая принимает два void * в качестве параметров и возвращает int . Отсюда и актерский состав. Это безопасно, поскольку void * действует как общий указатель. Теперь перейдем к чтению объявления: возьмем объявление вашего strcmp :

 int strcmp(char *, char *);

Компилятор читает его как strcmp на самом деле:

 int (strcmp)(char *, char *)

функция (затухающая) на указатель на функцию в большинстве случаев), которая принимает два char * аргумента. Следовательно, тип указателя strcmp :

 int (*)(char *, char *)

Следовательно,

0
ответ дан 8 December 2019 в 05:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: