Определите функцию, имя которой маскируется макросом - PullRequest
0 голосов
/ 19 января 2019

Иногда бывает удобно замаскировать функцию макросом с тем же именем. В этом надуманном примере макросы позволяют вставить дополнительную проверку при вызове function().

int function(int i);

#define function(i)  ( assert(i>0), function(i) )

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

В соответствующем блоке определение function() теперь имеет проблему: function теперь является макросом. Так что int function(int i) { ... } будет расширен и довольно сильно потерпит неудачу.

Решение этой проблемы простое: просто #undef function перед определением, а затем реализуйте функцию.

Все хорошо, кроме этого ...

Если в последующем разделе того же модуля другая функция вызывает function(), теперь она будет вызывать символ напрямую, а не макрос в *.h, таким образом теряя дополнительные функции, предоставляемые макросами, что может быть нежелательно.

Еще один способ решения этой проблемы доступен в gcc с использованием расширения компилятора #pragma push_macro. Это работает, но довольно уродливо, добавляя минимум 3 строки вокруг определения функции, что не способствует удобочитаемости. И это без учета переносимости махинаций, что добавит больше сложности.

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

Я подозреваю, что может существовать лучшее решение этой проблемы. Есть идеи?

Ответы [ 2 ]

0 голосов
/ 19 января 2019

Иногда бывает удобно замаскировать функцию с помощью макроса с тем же именем.

Макроподобные функции-оболочки, такие как

static inline int actual_function(int i)
{
    /* extra stuff */
    return function(i);
}

, являютсялучший вариант во время компиляции, из-за принципа наименьшего сюрприза.(Например, вы удивляете разработчиков, они делают глупости. Поэтому, чем меньше сюрпризов, тем меньше глупых ошибок они могут совершить.)

К сожалению, это не помогает с изменением названия.Мне лично все равно, потому что переименование все равно всего на один быстрый find . -name '*.[ch]' -exec sed -e 's|\bOLDNAME\b|NEWNAME|g' -i '{}' ';'.


Для динамически связанных символов мы можем обернуть или вставить их своими собственными,во время выполнения.Это сильно зависит от ОС и набора инструментов.

В Linux есть два варианта: использование средств динамического компоновщика (dlsym()) или параметр компоновщика --wrap.Он работает только с динамически связанными символами, но обычно, по крайней мере, стандартная библиотека связана динамически.

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

#define  _GNU_SOURCE
#include <stdlib.h>
#include <dlfcn.h>

static void *(*real_malloc)(size_t) = NULL;

void *malloc(size_t size)
{
    if (!real_malloc)
        real_malloc = dlsym(RTLD_NEXT, "malloc");
    /* extra stuff */
    return real_malloc(size);
}

Если вы хотите выполнить вышеописанное в поточно-ориентированном режиме, это немного усложняется.(Я использую __atomic_load_n() и т. Д., Так что это всего лишь несколько строк кода.)

Проще всего сказать, что GCC должен сделать для нас магию символов, предоставив ей опцию -Wl,-wrap,malloc при компиляциии связывание двоичного файла.Затем

#include <stdlib.h>

void *__real_malloc(size_t);

void *__wrap_malloc(size_t size)
{
    /* extra stuff */
    return __real_malloc(size);
}

На этот раз вставка / перенос выполняется на уровне таблицы символов.

0 голосов
/ 19 января 2019

Альтернативный трюк для функционально-подобных макросов - поместить избыточные скобки вокруг объявления в определении:

int (function)(int i) {
    ...
}

Это предотвращает сопоставление и расширение функционально-подобного макроса, но не влияет на определение.

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