4

看看是否有人知道是否可以交换 C 函数......?

 void swap2(int(*a)(int), int(*b)(int)) {
   int(*temp)(int) = a;
   *a = *b;
   *b = temp;
   // Gives 'Non-object type 'int (int)' is not assignable
 }

 swap2(&funcA, &funcB);

编辑

这里有更多关于意图的数据——下面提供了一些答案,这些答案确实有效,例如使用创建函数 ptr typedef,将它们指向函数并切换它们,这样您就可以成功调用新的交换 ptrs。

但是在交换后用它们的原始名称调用函数显示没有变化。本质上,我正在寻找相当于 objc“swizzle”的 ac。

我开始认为这是不可能的,因为 c 完全缺乏反射,并且需要实际修改二进制文件本身(显然不可行)。丁:

欢迎评论。

4

5 回答 5

9

如果您使用如下函数指针,则可以

typedef int (*func_pt)(int);

func_pt a, b;

void swap(func_pt * a, func_pt * b)
{
    func_pt tmp = *b;
    *b = *a;
    *a = tmp;
}

swap(&a, &b);

或者你这样用,我认为不是:

int test1(int a)
{
    return a;
}

int test2(int b)
{
    return b;
}

swap(&test1, &test2);

完成编译工作程序

#include <stdio.h>
#include <stdlib.h>

typedef int (* func_pt)(int);

func_pt a, b;

int test1(int a)
{
    printf("test1\n");
    return 1;
}

int test2(int a)
{
    printf("test2\n");
    return 2;
}

void swap(func_pt * a, func_pt * b)
{
    func_pt tmp = *b;

    *b = *a;
    *a = tmp;
}

int main(void)
{
    a = &test1;
    b = &test2;

    printf("before\n");
    a(1);
    b(1);

    swap(&a, &b);

    printf("after\n");
    a(1);
    b(2);

    return 0;

}

输出:

before
test1
test2
after
test2
test1

有的人自己不去尝试,就说很荒唐。所以我给你举个例子。

于 2013-05-16T05:42:44.367 回答
3

我很确定您需要指向函数指针的指针来交换指针,不是吗?这种类型的交换函数交换值;你真的想处理地址。示例函数调用不会真正起作用,因为 C 不将函数视为一等变量,因此您实际上不能直接交换函数;您需要使用指向函数地址的指针,因为可以交换地址:

void swap2(int(**a)(int), int(**b)(int)) {
   int(*temp)(int) = *a;
   *a = *b;
   *b = *temp;
}

int(*func1)(int) = &foo;
int(*func2)(int) = &bar;

swap2(&func1, &func2);
于 2013-05-16T05:43:59.230 回答
1

是的你可以。认为函数指针只是一个内存地址,唯一的要求是:保存此类地址的位置需要是可变的。说起来,int (*foo)()还真不至于指向哪里foo。可能是printf()fopen()

于 2013-05-18T17:46:28.830 回答
1

您的代码在分配时会给出类似“invalid lvalue”的错误。正如我在您的代码中看到的那样,您正在尝试在不更改其值的情况下交换指针,因此请查看以下解决方案。

void swap2(int(**a)(int), int(**b)(int)) {   
   int(*temp)(int) = *a;
   *a = *b;
   *b = temp;
}

int main(){
    int(*temp1)(int) = &funcA;
    int(*temp2)(int) = &funcB;
    swap2(&temp1,&temp2);
}
于 2013-05-16T06:07:18.437 回答
0

尽管该主题询问有关交换功能的问题,但您实际上想模仿交换功能swizzle。这只是意味着您希望能够调用相同的函数名称,但让它做一些不同的事情。

仅指针的解决方案不会给您这种行为。如果这对您来说不重要,那么您应该采用仅提供的函数指针解决方案之一。如果它对您重要,那么您将需要引入一个抽象层。抽象可以在底层使用函数指针(尽管还有其他解决方案)。

此接口用户的 API 将是:

/* API to initialize */
void abstract_func_init ();

/* API to manipulate abstract functions */
typedef int abstract_func_type ();
abstract_func_type * abstract_func_get (abstract_func_type *key);
int abstract_func_set (abstract_func_type *key, abstract_func_type *behavior);

/* the abstract functions */
extern int foo ();
extern int bar ();

这种接口的实现可能如下所示:

static void insert (abstract_func_type *key, abstract_func_type **behavior)
{ /* associate key to behavior */ }
static abstract_func_type ** lookup (abstract_func_type *key)
{ /* return behavior from key */ }

abstract_func_type * abstract_func_get (abstract_func_type *k) {
    abstract_func_type **f = lookup(k);
    if (f) return *f;
    return 0;
}

int abstract_func_set (abstract_func_type *k, abstract_func_type *p) {
    abstract_func_type **f = lookup(k);
    if (f) {
        *f = p;
        return 0;
    }
    return -ENOENT;
}

#define DEFINE_ABSTRACT_FUNC(func) \
    static int static_##func (); \
    static abstract_func_type *func##_ptr = static_##func; \
    int func () { return func##_ptr(); } \
    static int static_##func ()

DEFINE_ABSTRACT_FUNC(foo) { return puts("foo"); }
DEFINE_ABSTRACT_FUNC(bar) { return puts("bar"); }

void abstract_func_init () {
    insert(foo, &foo_ptr);
    insert(bar, &bar_ptr);
}

然后,swap()您最初在帖子中提出的内容可以这样实现:

void swap (abstract_func_type *a, abstract_func_type *b) {
    abstract_func_type *ap = abstract_func_get(a);
    abstract_func_type *bp = abstract_func_get(b);
    abstract_func_set(a, bp);
    abstract_func_set(b, ap);
}

这是一个调用的程序swap()

    puts("before swap");
    foo();
    bar();
    swap(foo, bar);
    puts("after swap");
    foo();
    bar();

它的输出是:

before swap
foo
bar
after swap
bar
foo

为了自动将抽象函数添加到查找表中,您可以在构建系统中引入一个额外的步骤,该步骤调用一个脚本,该脚本会grep输出行,并生成一个新的源文件,该文件具有一个函数,每个这样的行都有DEFINE_ABSTRACT_FUNC调用insert().

可以在此处找到模型的完整版本。

于 2013-05-16T18:41:29.010 回答