Вы можете использовать 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;
}
🏠
То, что здесь происходит, действительно является актерским составом. Давайте на секунду проигнорируем троичный и притворимся, что numcmp всегда используется. Для целей этого вопроса функции могут выступать в качестве указателей на функции в C. Поэтому, если вы посмотрите на тип числового значения, то на самом деле это
(int (*)(int*,int*))
. Для того, чтобы это правильно использовалось в qsort, у него должны быть параметры void. Поскольку все типы здесь имеют одинаковый размер по отношению к параметрам и возвращаемым типам, можно заменить на другой. Все, что нужно, это приведение, чтобы сделать компилятор счастливым.
(int (*)(void*,void*))(numcmp )
Вы пропустили трюк - часть
(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);
Я бы, наверное, прочитал это так:
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);
Пример в вопросе имеет явный случай.
Кто бы ни написал этот фрагмент кода, он пытался быть слишком умным . По его мнению, он, вероятно, думает, что он хороший программист, делая умную «однострочку». На самом деле, он делает код, который будет менее читабельным и с которым трудно работать в долгосрочной перспективе и должен быть переписан в более очевидной форме, похожей на код Харпера Шелби.
Помните пословицу Брайана Керниган:
Отладка вдвое сложнее, чем запись код в первую очередь. Поэтому, если вы напишите код как умно, насколько это возможно, вы, по определение, недостаточно умное для отладки Это.
Я делаю много критичного к производительности кодирования с жесткими сроками в реальном времени ... и я до сих пор не видел места, где бы подходил плотный однострочный.
Я даже возился с компиляцией и проверкой asm, чтобы увидеть, имеет ли однострочная версия лучшую скомпилированную реализацию asm, но я никогда не находил, что однострочник того стоит.
Ваша логика верна, я думаю. Это действительно приведение к «указателю на функцию, которая получает два указателя void и возвращает int», который является обязательным типом по сигнатуре метода.
Вы можете сделать это без приведения указателя функции. Вот как как . По моему опыту, в большинстве мест, если вы используете актерский состав, вы делаете это неправильно.
Как уже указывали другие, для
(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>
Обратите внимание, что стандартное определение 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, ...);
В современном стиле написано:
Оба numcmp
и strcmp
являются указателями на функции, которые принимают два char *
в качестве параметров и возвращает int
. Подпрограмма qsort
ожидает указатель на функцию, которая принимает два void *
в качестве параметров и возвращает int
. Отсюда и актерский состав. Это безопасно, поскольку void *
действует как общий указатель. Теперь перейдем к чтению объявления: возьмем объявление вашего strcmp
:
int strcmp(char *, char *);
Компилятор читает его как strcmp
на самом деле:
int (strcmp)(char *, char *)
функция (затухающая) на указатель на функцию в большинстве случаев), которая принимает два char *
аргумента. Следовательно, тип указателя strcmp
:
int (*)(char *, char *)
Следовательно,