可以交换C函数吗?
看看是否有人知道是否可以交换C函数可以交换C函数吗?,c,pointers,function-pointers,C,Pointers,Function Pointers,看看是否有人知道是否可以交换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); 编辑 这里提供了更多关于意图的数据——下面提供了一些答案,这些答案可以起作用,例如使用t
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);
编辑
这里提供了更多关于意图的数据——下面提供了一些答案,这些答案可以起作用,例如使用typedef
创建函数ptr,将它们指向函数并切换这些函数,从而使您能够成功调用新的交换ptr
但在交换后按函数的原始名称调用函数并没有改变。本质上,我在寻找一个与objc“swizzle”等价的c
我开始认为这是不可能的,因为c完全没有反射,并且需要实际修改二进制本身(显然不可行)。D:
欢迎评论。如果您使用下面的函数指针,则是肯定的
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;
}
有些人不亲自尝试,只是说它很荒谬。所以我给你举个例子。我很确定你需要函数指针的指针来交换指针,不是吗?这种类型的交换函数交换值;你真的想处理地址。示例函数调用不会真正起作用,因为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);
您的代码在赋值时会出现类似“无效左值”的错误。正如我在代码中看到的,您试图在不更改其值的情况下交换指针,所以请查看下面的解决方案
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);
}
尽管主题询问交换函数,但实际上您希望模拟
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 ();
before swap
foo
bar
after swap
bar
foo
此类接口的实现可能如下所示:
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()
的程序:
其产出将是:
/* 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 ();
before swap
foo
bar
after swap
bar
foo
为了自动将抽象函数添加到查找表中,您可以在构建系统中引入一个额外的步骤,该步骤调用一个脚本,该脚本将grep
输出DEFINE\u abstract\u FUNC
行,并生成一个新的源文件,该文件中的每个行都有一个调用insert()
的函数
可以找到模型的完整版本。可以。假设一个函数指针只是一个内存地址,唯一的问题是:在哪里保存这样的地址需要是可变的。比如说,
int(*foo)(
不是真正指向foo
指向的地方。在*b=temp
中,可能是到printf()
或fopen()
*b
是完全荒谬的。你只能在调用函数指针时取消引用它。*b
一开始就不是一个有效的左值。@Thokchom--虽然该注释似乎主要是关键性的,而不是建设性的,关键是你是对的。该函数是针对其他数据类型的通用指针交换的改编,显然是不正确的,因此我首先要问的问题是**请参见编辑**不,不,你误解了我。我为什么要批评你?我只是在谈论那项任务。我用粗体写了“荒谬”以引起你的注意。干杯@MilesAlden关于编辑部分:能够在运行时交换函数需要运行时决定调用哪个函数。有些语言可能有语法上的甜头,但它总是归结为某种查找,查找要调用的内容(或者在调用函数的每个地方修改二进制,这甚至常常被操作系统禁止)。在C语言中,如果您想实现这一点,就需要显式地实现,函数指针是最直接的方法(但不是唯一的方法)。在C语言中,你必须自己实现反射特性,在你需要的地方。这在函数范围内有效,但不会改变实际的函数指针地址。打印之前和之后的函数指针,您将看到。就像您可以调用func1()&func2(),它们现在被交换,但是调用foo()&bar()会显示它们不受影响。函数地址是常量;在正确的条件下,如代码段实际上是可写的,或执行许多汇编级的向导,并且如果星对齐,则不会使计算机崩溃,您不需要付出更多的努力就无法在C中移动代码:D.这确实起到了您描述的作用,使交换typedef'D ptr成为可能,如果你叫他们,他们就被打翻了;然而,我对第二个例子更感兴趣。我本质上是在寻找规则c函数在objective-c中的swizzling的等价物。这里我们调用这些指针,但是如果我调用test1(1),它仍然调用test1(),而不是test2()。有什么想法吗?@MilesAlden:函数名是“地址常量”。标准C不允许您更改它们,如果您以某种方式设法更改,则允许您启动计算机。如果您想随意切换实现,就必须有表示每个实现的函数指针,并始终通过这些指针调用函数。不过,这实际上扼杀了许多形式的优化。“允许您点燃计算机…”只是对这一点大笑,谢谢。:-)是的,这就是我在这里收集的。@cHao说UB是如何允许编译器启动编译器的,这很有趣,但它太不准确了,已经过时了。事实上,这并不适合我