Переопределите вызов функции в C

Вы можете использовать .loc с repeat, например

In [295]: df.loc[df.index.repeat(df['count'])].reset_index(drop=True)
Out[295]:
   x  count
0  d      2
1  d      2
2  e      3
3  e      3
4  e      3
5  f      2
6  f      2

Или, используя pd.Series.repeat, вы можете

In [278]: df.set_index('x')['count'].repeat(df['count']).reset_index()
Out[278]:
   x  count
0  d      2
1  d      2
2  e      3
3  e      3
4  e      3
5  f      2
6  f      2
68
задан Tim Post 6 March 2009 в 03:04
поделиться

8 ответов

Если это только для Вашего источника, что Вы хотите получить/изменить вызовы, простое решение состоит в том, чтобы соединить заголовочный файл (intercept.h) с:

#ifdef INTERCEPT
    #define getObjectName(x) myGetObectName(x)
#endif

и реализация функция следующим образом (в intercept.c, который не делает , включают intercept.h):

const char *myGetObjectName (object *anObject) {
    if (anObject == NULL)
        return "(null)";
    else
        return getObjectName(anObject);
}

Тогда удостоверяются каждый исходный файл, где Вы хотите прервать вызов, имеет:

#include "intercept.h"

наверху.

Затем то, когда Вы компилируете с" -DINTERCEPT", все файлы вызовут Вашу функцию, а не реальную и Вашу функцию, может все еще назвать реальный.

Компиляция без" -DINTERCEPT" будет препятствовать тому, чтобы перехват произошел.

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

68
ответ дан paxdiablo 7 November 2019 в 10:01
поделиться

С gcc в соответствии с Linux можно использовать --wrap флаг компоновщика как это:

gcc program.c -Wl,-wrap,getObjectName -o program

и определяют Вашу функцию как:

const char *__wrap_getObjectName (object *anObject)
{
    if (anObject == NULL)
        return "(null)";
    else
        return __real_getObjectName( anObject ); // call the real function
}

Это гарантирует, что все вызовы к getObjectName() перенаправлены к Вашей функции обертки (во время ссылки). Этот очень полезный флаг однако отсутствует в gcc в соответствии с Mac OS X.

Не забывают объявлять функцию обертки с extern "C", если Вы компилируете с g ++ все же.

77
ответ дан codelogic 7 November 2019 в 10:01
поделиться

Можно переопределить функцию с помощью LD_PRELOAD, прием - видит man ld.so. Вы компилируете совместно использованный lib со своей функцией и запускаете двоичный файл (Вы даже не должны изменять двоичный файл!) как LD_PRELOAD=mylib.so myprog.

В теле Вашей функции (в общем lib) Вы пишете как это:

const char *getObjectName (object *anObject) {
  static char * (*func)();

  if(!func)
    func = (char *(*)()) dlsym(RTLD_NEXT, "getObjectName");
  printf("Overridden!\n");     
  return(func(anObject));    // call original function
}

можно переопределить любую функцию из общей библиотеки, даже из stdlib, не изменяя/перекомпилировав программу, таким образом, Вы могли добиться цели на программах, у Вас нет источника для. Разве это не хорошо?

37
ответ дан Benjamin 7 November 2019 в 10:01
поделиться

часто желательно изменить поведение существующих кодовых баз путем обертывания или замены функций. Когда редактирование исходного кода тех функций является жизнеспособным вариантом, это может быть простым процессом. Когда источник функций не может быть отредактирован (например, если функции обеспечиваются системной библиотекой C), то альтернативные методы требуются. Здесь, мы представляем такие методы для UNIX, Windows и платформ OS X Macintosh.

Это - большое покрытие PDF, как это было сделано на OS X, Linux и Windows.

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

Прерывающие произвольные функции в Windows, UNIX и платформах OS X Macintosh (2004), Daniel S. Myers и Adam L. Bazinet .

Вы можете загружать PDF непосредственно с альтернативного местоположения (для дублирования) .

И наконец, должен, предыдущие два источника так или иначе понизиться в провокационных сообщениях, вот результат поиска Google для него .

10
ответ дан Kuba Ober 7 November 2019 в 10:01
поделиться

При использовании GCC можно сделать функцию weak. Они может быть переопределен неслабыми функциями:

test.c:

#include <stdio.h>

__attribute__((weak)) void test(void) { 
    printf("not overridden!\n"); 
}

int main() {
    test();
}

, Что это делает?

$ gcc test.c
$ ./a.out
not overridden!

test1.c:

#include <stdio.h>

void test(void) {
    printf("overridden!\n");
}

, Что это делает?

$ gcc test1.c test.c
$ ./a.out
overridden!

К сожалению, который не будет работать на другие компиляторы. Но у Вас могут быть слабые объявления, которые содержат переопределяемые функции в их собственном файле, помещая просто включение в файлы реализации API, если Вы компилируете использование GCC:

weakdecls.h:

__attribute__((weak)) void test(void);
... other weak function declarations ...

functions.c:

/* for GCC, these will become weak definitions */
#ifdef __GNUC__
#include "weakdecls.h"
#endif

void test(void) { 
    ...
}

... other functions ...

Оборотная сторона этого - то, что это не работает полностью , не делая чего-то в файлы API (нуждающийся в тех трех строках и weakdecls). Но как только Вы сделали то изменение, функции могут быть переопределены легко путем записи глобального определения в одном файле и соединения этого в.

26
ответ дан Johannes Schaub - litb 7 November 2019 в 10:01
поделиться

Можно определить указатель функции как глобальную переменную. Синтаксис вызывающих сторон не изменился бы. Когда Ваша программа запускается, она могла проверить, установлены ли некоторый флаг командной строки или переменная среды позволить регистрироваться, затем сохранить исходное значение указателя функции и заменить его Вашей функцией входа. Вам не был бы нужен специальный "вход, включенный" сборка. Пользователи могли позволить регистрироваться "в поле".

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

foo.h:

typedef const char* (*GetObjectNameFuncPtr)(object *anObject);
extern GetObjectNameFuncPtr GetObjectName;

foo.cpp:

const char* GetObjectName_real(object *anObject)
{
    return "object name";
}

const char* GetObjectName_logging(object *anObject)
{
    if (anObject == null)
        return "(null)";
    else
        return GetObjectName_real(anObject);
}

GetObjectNameFuncPtr GetObjectName = GetObjectName_real;

void main()
{
    GetObjectName(NULL); // calls GetObjectName_real();

    if (isLoggingEnabled)
        GetObjectName = GetObjectName_logging;

    GetObjectName(NULL); // calls GetObjectName_logging();
}
9
ответ дан Chris Peterson 7 November 2019 в 10:01
поделиться

Существует также хитрый метод выполнения его в компоновщике, вовлекающем две тупиковых библиотеки.

Библиотека № 1 связана против библиотеки хоста и представляет символ, переопределяемый под другим именем.

Библиотека № 2 связана против библиотеки № 1, interecepting вызов и вызов переопределенной версии в библиотеке № 1.

Быть очень осторожной с заказами ссылки здесь, или она не будет работать.

3
ответ дан Joshua 7 November 2019 в 10:01
поделиться

Вы могли пользоваться общей библиотекой (Unix), или DLL (Windows), чтобы сделать это также (будет определенная потеря производительности). Можно тогда измениться, DLL/так, чтобы загружается (одна версия для отладки, одна версия для неотладки).

я сделал подобную вещь в прошлом (для не достижения того, чего Вы пытаетесь достигнуть, но основная предпосылка является тем же), и это удалось хорошо.

[Редактирование на основе комментария OP]

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

существует два распространенных способа (что я знаю о) контакта с этим, общим lib/dll путем или записью различных реализаций, против которых Вы связываетесь.

Для обоих решений (совместно использованный освобождает или другое соединение) у Вас был бы foo_linux.c, foo_osx.c, foo_win32.c (или лучшим путем является linux/foo.c, osx/foo.c и win32/foo.c), и затем скомпилируйте и свяжитесь с соответствующим.

, Если бы Вы ищете и другой код для различных платформ И отлаживаете выпуск-vs-, я, вероятно, был бы склонен пойти с общим решением lib/DLL, поскольку это является самым гибким.

0
ответ дан TofuBeer 7 November 2019 в 10:01
поделиться
Другие вопросы по тегам:

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