C中函数指针的复合谓词
Composite Predicate of function pointers in C
我正在尝试使用函数指针构建复合谓词。
不知道可不可以。
我的谓词是这样的形式:int (*predicate)(int)
那些工作正常。
我想创建一个函数,它接受 2 个 int (*predicate)(int)
类型的参数,return 是一个 int (*predicate)(int)
类型的函数,这样新函数 returns a(x) && b(x) 的值。
我想做这样的东西:
int ( *composite(int (*a)(int), int (*b)(int)) )(int x) {
return a(x) && b(x);
}
或:
int ( *negate(int (*a)(int)) )(int x) {
return !a(x);
}
我知道我的尝试是 return 一个值,而不是一个函数,但是如果我尝试为它们创建另一个函数 return,我最终会遇到完全相同的问题。
如果我这样做:
int composed(int (*a)(int), int (*b)(int), int x ) {
return a(x) && b(x);
}
它可以编译,但它不再是 int (*predicate)(int)
类型,所以我无法按我想要的方式使用它。
我应该怎么做?
附上完整示例代码供参考:
#include <stdio.h>
unsigned int count(const int* xs, unsigned int len, int (*predicate)(int)) {
int c = 0;
for(int i = 0; i < len; i++) {
if(predicate(xs[i])) c++;
}
return c;
}
int isEven(int x) { return x % 2 == 0; }
int isOdd(int x) { return !isEven(x); }
int isPos(int x) { return x > 0; }
int isNeg(int x) { return x < 0; }
// int composed(int (*a)(int), int (*b)(int), int x ) {
// return a(x) && b(x);
// }
//
// int ( *composite(int (*a)(int), int (*b)(int)) )(int x) {
// return &composed(a,b)(x)
// }
int main() {
int xs[] = {-5,-4,-3,-2,-1,0,1,2,3,4,5};
const int len = 11;
printf("Even: %d\n", count(xs, len, &isEven));
printf(" Odd: %d\n", count(xs, len, &isOdd));
printf(" Pos: %d\n", count(xs, len, &isPos));
printf(" Neg: %d\n", count(xs, len, &isNeg));
// int (*compositePtr)(int) = composite(&isNeg, &isOdd);
// printf("Odd & Neg: %d", count(xs, len, compositePtr));
}
我曾经为了演示目的写过如下代码:
#include <stdio.h>
/* one int for the implicit parameter n,
* one int as return type,
* one int as parameter.
*/
typedef struct int_int_int_closure {
int (*call)(const struct int_int_int_closure *, int);
int n;
} int_int_int_closure;
static int
adderfn(const int_int_int_closure *cl, int n) {
return cl->n + n;
}
int
main(void)
{
int_int_int_closure a3;
a3.call = adderfn;
a3.n = 3;
printf("%d\n", a3.call(&a3, 2));
return 0;
}
您可以概括此代码,使闭包由函数指针、指向其数据的指针和数据大小组成。
您不能在 C 中动态创建闭包或函数,因此您需要做一些其他事情。最简单的方法是使用额外的间接级别。如果您将谓词更改为
int (**predicate)(void *, int)
你称之为 (**predicate)(predicate, x)
,那么你可以很容易地创建新的动态谓词:
typedef int (*predicate_t)(void *, int);
struct compose_fn_data {
predicate_t fn, *a, *b;
};
int and_fn(void *data_, int x) {
struct compose_fn_data *data = data_;
return (**data->a)(data->a, x) && (**data->b)(data->b, x);
}
int or_fn(void *data_, int x) {
struct compose_fn_data *data = data_;
return (**data->a)(data->a, x) || (**data->b)(data->b, x);
}
predicate_t *compose(predicate_t fn, predicate_t *a, predicate_t *b) {
struct compose_fn_data *rv = malloc(sizeof *rv);
rv->fn = fn;
rv->a = a;
rv->b = b;
return &rv->fn;
}
predicate_t *and(predicate_t *a, predicate_t *b) { return compose(and_fn, a, b); }
predicate_t *or(predicate_t *a, predicate_t *b) { return compose(or_fn, a, b); }
关于这个的小烦恼是对于简单的函数,您需要定义一个额外的单字数据结构来保存函数指针,只是为了间接通过它。您通常使用函数定义旁边的全局变量来执行此操作:
int isEven_fn(void *data, int x) { (void)data; return x % 2 == 0; }
predicate_t isEven = isEven_fn;
int isOdd_fn(void *data, int x) { return !isEven_fn(data, x); }
predicate_t isOdd = isOdd_fn;
int isPos_fn(void *data, int x) { (void)data; return x > 0; }
predicate_t isPos = isPos_fn;
int isNeg_fn(void *data, int x) { (void)data; return x < 0; }
predicate_t isNeg = isNeg_fn;
现在您可以执行以下操作:
printf("Even: %d\n", count(xs, len, &isEven));
printf("Odd & Neg: %d", count(xs, len, and(&isNeg, &isOdd)));
printf("%d", count(xs, len, or(and(&isNeg, &isOdd), &isEven)));
尽管后者确实会泄漏内存。
当发明传递函数指针to/from函数的语法时,我怀疑抽了很多没说的东西。
给定函数指针 int (*)(int)
,函数 returning 这样的函数指针声明为:
int (*func(void))(int);
1 2 3
其中1=return函数指针的类型,2是函数的参数列表,3=函数指针的参数列表。
现在如果你想创建一个函数 returning 一个这样的指针,并将两个这样的指针作为参数,它是 trivial:
int (*func(int(*a)(int), int(*b)(int)))(int)
不,这不是微不足道的……这太疯狂了!如果您真的可以编写和理解这样的代码,那么这意味着您只是为了自己的利益而使用 C 太多了。
你绝对应该做的是使用 typedef
.
typedef int (predicate_t)(int);
...
predicate_t* func (predicate_t* a, predicate_t* b);
但是,我怀疑您实际上只需要一个 return 是整数而不是函数指针的函数。
这是您创建谓词函数组合的 block-based 实现:
//
// ViewController.m
// PredicateFunctionsExercise
//
// Created by James Alan Bush on 3/12/22.
//
#import "ViewController.h"
@import simd;
typedef int (^boolean_expression)(void);
typedef int (^guarded_boolean_expression)(void);
typedef int (^ const (*guarded_boolean_expression_t))(void);
typedef int (^(^conditional_boolean_expression)(guarded_boolean_expression_t))(void);
typedef int (^ const (^ const (*conditional_boolean_expression_t))(guarded_boolean_expression_t))(void);
typedef int (^predicate)(void);
typedef int (^ const (*predicate_t))(void);
static int c = 0;
static int flag = (1 << 0);
guarded_boolean_expression flag_conditional = ^ int { return flag; };
conditional_boolean_expression isEven = ^ (guarded_boolean_expression_t _Nullable x) { return ^ int { int result = (*x)() % 2 == 0; printf("%d %s (%d)\t", flag, (result) ? "is even" : "is not even", result); return result; }; };
conditional_boolean_expression isOdd = ^ (guarded_boolean_expression_t _Nullable x) { return ^ int { int result = (*x)() % 2 == 1; printf("%d %s (%d)\t", flag, (result) ? "is odd" : "is not odd", result); return result; }; };
conditional_boolean_expression isPos = ^ (guarded_boolean_expression_t _Nullable x) { return ^ int { int result = (*x)() > 0; printf("%d %s (%d)\t", flag, (result) ? "is positive" : "is not positive", result); return result; }; };
conditional_boolean_expression isNeg = ^ (guarded_boolean_expression_t _Nullable x) { return ^ int { int result = (*x)() < 0; printf("%d %s (%d)\t", flag, (result) ? "is negative" : "is not negative", result); return result; }; };
static void (^evaluate_predicate)(predicate_t) = ^ (predicate_t p) {
printf("\nresult = %d (%d invocations)\n", (*p)(), c);
};
static int (^(^(^g)(__strong conditional_boolean_expression, __strong conditional_boolean_expression, guarded_boolean_expression_t))(int (^__strong)(conditional_boolean_expression_t, conditional_boolean_expression_t, guarded_boolean_expression_t)))(void) =
^ (conditional_boolean_expression boolean_conditional_a, conditional_boolean_expression boolean_conditional_b, guarded_boolean_expression_t guarded_conditional) {
return ^ (int (^bitwise_operation)(conditional_boolean_expression_t, conditional_boolean_expression_t, guarded_boolean_expression_t)) {
return ^ (int boolean_expression) {
return ^ int {
++c;
return boolean_expression;
};
}(bitwise_operation((conditional_boolean_expression_t)&boolean_conditional_a, (conditional_boolean_expression_t)&boolean_conditional_b, guarded_conditional));
};
};
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// gbe_a is set to a precalculated and stored result
// Invoking gbe_a() merely returns the results without recalculating it -- perfect for use inside the domain of discourse
guarded_boolean_expression gbe_a = g(isEven, isOdd, &flag_conditional)(^ int (conditional_boolean_expression_t boolean_conditional_a, conditional_boolean_expression_t boolean_conditional_b, guarded_boolean_expression_t guarded_conditional) {
return ((*boolean_conditional_a)(guarded_conditional)() & (*guarded_conditional)()) && (*boolean_conditional_b)(guarded_conditional);
});
guarded_boolean_expression gbe_b = g(isPos, isNeg, &flag_conditional)(^ int (conditional_boolean_expression_t boolean_conditional_a, conditional_boolean_expression_t boolean_conditional_b, guarded_boolean_expression_t guarded_conditional) {
return ((*boolean_conditional_a)(guarded_conditional)() & (*guarded_conditional)()) && (*boolean_conditional_b)(guarded_conditional);
});
// Returning a variety of bitwise operations with randomly chosen operands and operators
// to demonstrate that simd vectors can be used combining multiple bitwise operations into a single operation
simd_uint2 bit_vector = simd_make_uint2((gbe_a() << 0), (gbe_b() << 0));
simd_uint2 bit_mask = simd_make_uint2(flag, flag);
simd_uint2 results = simd_make_uint2(bit_vector & bit_mask);
printf("\n%d & %d == %d\t\t\t", bit_vector[0], bit_mask[0], results[0]);
printf("%d & %d == %d\n", bit_vector[1], bit_mask[1], results[1]);
results = simd_make_uint2(bit_vector | bit_mask);
printf("%d | %d == %d\t\t\t", bit_vector[0], bit_mask[0], results[0]);
printf("%d | %d == %d\n", bit_vector[1], bit_mask[1], results[1]);
results = simd_make_uint2(bit_vector ^ bit_mask);
printf("%d ^ %d == %d\t\t\t", bit_vector[0], bit_mask[0], results[0]);
printf("%d ^ %d == %d\n", bit_vector[1], bit_mask[1], results[1]);
}
@end
控制台输出:
我正在尝试使用函数指针构建复合谓词。 不知道可不可以。
我的谓词是这样的形式:int (*predicate)(int)
那些工作正常。
我想创建一个函数,它接受 2 个 int (*predicate)(int)
类型的参数,return 是一个 int (*predicate)(int)
类型的函数,这样新函数 returns a(x) && b(x) 的值。
我想做这样的东西:
int ( *composite(int (*a)(int), int (*b)(int)) )(int x) {
return a(x) && b(x);
}
或:
int ( *negate(int (*a)(int)) )(int x) {
return !a(x);
}
我知道我的尝试是 return 一个值,而不是一个函数,但是如果我尝试为它们创建另一个函数 return,我最终会遇到完全相同的问题。
如果我这样做:
int composed(int (*a)(int), int (*b)(int), int x ) {
return a(x) && b(x);
}
它可以编译,但它不再是 int (*predicate)(int)
类型,所以我无法按我想要的方式使用它。
我应该怎么做?
附上完整示例代码供参考:
#include <stdio.h>
unsigned int count(const int* xs, unsigned int len, int (*predicate)(int)) {
int c = 0;
for(int i = 0; i < len; i++) {
if(predicate(xs[i])) c++;
}
return c;
}
int isEven(int x) { return x % 2 == 0; }
int isOdd(int x) { return !isEven(x); }
int isPos(int x) { return x > 0; }
int isNeg(int x) { return x < 0; }
// int composed(int (*a)(int), int (*b)(int), int x ) {
// return a(x) && b(x);
// }
//
// int ( *composite(int (*a)(int), int (*b)(int)) )(int x) {
// return &composed(a,b)(x)
// }
int main() {
int xs[] = {-5,-4,-3,-2,-1,0,1,2,3,4,5};
const int len = 11;
printf("Even: %d\n", count(xs, len, &isEven));
printf(" Odd: %d\n", count(xs, len, &isOdd));
printf(" Pos: %d\n", count(xs, len, &isPos));
printf(" Neg: %d\n", count(xs, len, &isNeg));
// int (*compositePtr)(int) = composite(&isNeg, &isOdd);
// printf("Odd & Neg: %d", count(xs, len, compositePtr));
}
我曾经为了演示目的写过如下代码:
#include <stdio.h>
/* one int for the implicit parameter n,
* one int as return type,
* one int as parameter.
*/
typedef struct int_int_int_closure {
int (*call)(const struct int_int_int_closure *, int);
int n;
} int_int_int_closure;
static int
adderfn(const int_int_int_closure *cl, int n) {
return cl->n + n;
}
int
main(void)
{
int_int_int_closure a3;
a3.call = adderfn;
a3.n = 3;
printf("%d\n", a3.call(&a3, 2));
return 0;
}
您可以概括此代码,使闭包由函数指针、指向其数据的指针和数据大小组成。
您不能在 C 中动态创建闭包或函数,因此您需要做一些其他事情。最简单的方法是使用额外的间接级别。如果您将谓词更改为
int (**predicate)(void *, int)
你称之为 (**predicate)(predicate, x)
,那么你可以很容易地创建新的动态谓词:
typedef int (*predicate_t)(void *, int);
struct compose_fn_data {
predicate_t fn, *a, *b;
};
int and_fn(void *data_, int x) {
struct compose_fn_data *data = data_;
return (**data->a)(data->a, x) && (**data->b)(data->b, x);
}
int or_fn(void *data_, int x) {
struct compose_fn_data *data = data_;
return (**data->a)(data->a, x) || (**data->b)(data->b, x);
}
predicate_t *compose(predicate_t fn, predicate_t *a, predicate_t *b) {
struct compose_fn_data *rv = malloc(sizeof *rv);
rv->fn = fn;
rv->a = a;
rv->b = b;
return &rv->fn;
}
predicate_t *and(predicate_t *a, predicate_t *b) { return compose(and_fn, a, b); }
predicate_t *or(predicate_t *a, predicate_t *b) { return compose(or_fn, a, b); }
关于这个的小烦恼是对于简单的函数,您需要定义一个额外的单字数据结构来保存函数指针,只是为了间接通过它。您通常使用函数定义旁边的全局变量来执行此操作:
int isEven_fn(void *data, int x) { (void)data; return x % 2 == 0; }
predicate_t isEven = isEven_fn;
int isOdd_fn(void *data, int x) { return !isEven_fn(data, x); }
predicate_t isOdd = isOdd_fn;
int isPos_fn(void *data, int x) { (void)data; return x > 0; }
predicate_t isPos = isPos_fn;
int isNeg_fn(void *data, int x) { (void)data; return x < 0; }
predicate_t isNeg = isNeg_fn;
现在您可以执行以下操作:
printf("Even: %d\n", count(xs, len, &isEven));
printf("Odd & Neg: %d", count(xs, len, and(&isNeg, &isOdd)));
printf("%d", count(xs, len, or(and(&isNeg, &isOdd), &isEven)));
尽管后者确实会泄漏内存。
当发明传递函数指针to/from函数的语法时,我怀疑抽了很多没说的东西。
给定函数指针 int (*)(int)
,函数 returning 这样的函数指针声明为:
int (*func(void))(int);
1 2 3
其中1=return函数指针的类型,2是函数的参数列表,3=函数指针的参数列表。
现在如果你想创建一个函数 returning 一个这样的指针,并将两个这样的指针作为参数,它是 trivial:
int (*func(int(*a)(int), int(*b)(int)))(int)
不,这不是微不足道的……这太疯狂了!如果您真的可以编写和理解这样的代码,那么这意味着您只是为了自己的利益而使用 C 太多了。
你绝对应该做的是使用 typedef
.
typedef int (predicate_t)(int);
...
predicate_t* func (predicate_t* a, predicate_t* b);
但是,我怀疑您实际上只需要一个 return 是整数而不是函数指针的函数。
这是您创建谓词函数组合的 block-based 实现:
//
// ViewController.m
// PredicateFunctionsExercise
//
// Created by James Alan Bush on 3/12/22.
//
#import "ViewController.h"
@import simd;
typedef int (^boolean_expression)(void);
typedef int (^guarded_boolean_expression)(void);
typedef int (^ const (*guarded_boolean_expression_t))(void);
typedef int (^(^conditional_boolean_expression)(guarded_boolean_expression_t))(void);
typedef int (^ const (^ const (*conditional_boolean_expression_t))(guarded_boolean_expression_t))(void);
typedef int (^predicate)(void);
typedef int (^ const (*predicate_t))(void);
static int c = 0;
static int flag = (1 << 0);
guarded_boolean_expression flag_conditional = ^ int { return flag; };
conditional_boolean_expression isEven = ^ (guarded_boolean_expression_t _Nullable x) { return ^ int { int result = (*x)() % 2 == 0; printf("%d %s (%d)\t", flag, (result) ? "is even" : "is not even", result); return result; }; };
conditional_boolean_expression isOdd = ^ (guarded_boolean_expression_t _Nullable x) { return ^ int { int result = (*x)() % 2 == 1; printf("%d %s (%d)\t", flag, (result) ? "is odd" : "is not odd", result); return result; }; };
conditional_boolean_expression isPos = ^ (guarded_boolean_expression_t _Nullable x) { return ^ int { int result = (*x)() > 0; printf("%d %s (%d)\t", flag, (result) ? "is positive" : "is not positive", result); return result; }; };
conditional_boolean_expression isNeg = ^ (guarded_boolean_expression_t _Nullable x) { return ^ int { int result = (*x)() < 0; printf("%d %s (%d)\t", flag, (result) ? "is negative" : "is not negative", result); return result; }; };
static void (^evaluate_predicate)(predicate_t) = ^ (predicate_t p) {
printf("\nresult = %d (%d invocations)\n", (*p)(), c);
};
static int (^(^(^g)(__strong conditional_boolean_expression, __strong conditional_boolean_expression, guarded_boolean_expression_t))(int (^__strong)(conditional_boolean_expression_t, conditional_boolean_expression_t, guarded_boolean_expression_t)))(void) =
^ (conditional_boolean_expression boolean_conditional_a, conditional_boolean_expression boolean_conditional_b, guarded_boolean_expression_t guarded_conditional) {
return ^ (int (^bitwise_operation)(conditional_boolean_expression_t, conditional_boolean_expression_t, guarded_boolean_expression_t)) {
return ^ (int boolean_expression) {
return ^ int {
++c;
return boolean_expression;
};
}(bitwise_operation((conditional_boolean_expression_t)&boolean_conditional_a, (conditional_boolean_expression_t)&boolean_conditional_b, guarded_conditional));
};
};
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// gbe_a is set to a precalculated and stored result
// Invoking gbe_a() merely returns the results without recalculating it -- perfect for use inside the domain of discourse
guarded_boolean_expression gbe_a = g(isEven, isOdd, &flag_conditional)(^ int (conditional_boolean_expression_t boolean_conditional_a, conditional_boolean_expression_t boolean_conditional_b, guarded_boolean_expression_t guarded_conditional) {
return ((*boolean_conditional_a)(guarded_conditional)() & (*guarded_conditional)()) && (*boolean_conditional_b)(guarded_conditional);
});
guarded_boolean_expression gbe_b = g(isPos, isNeg, &flag_conditional)(^ int (conditional_boolean_expression_t boolean_conditional_a, conditional_boolean_expression_t boolean_conditional_b, guarded_boolean_expression_t guarded_conditional) {
return ((*boolean_conditional_a)(guarded_conditional)() & (*guarded_conditional)()) && (*boolean_conditional_b)(guarded_conditional);
});
// Returning a variety of bitwise operations with randomly chosen operands and operators
// to demonstrate that simd vectors can be used combining multiple bitwise operations into a single operation
simd_uint2 bit_vector = simd_make_uint2((gbe_a() << 0), (gbe_b() << 0));
simd_uint2 bit_mask = simd_make_uint2(flag, flag);
simd_uint2 results = simd_make_uint2(bit_vector & bit_mask);
printf("\n%d & %d == %d\t\t\t", bit_vector[0], bit_mask[0], results[0]);
printf("%d & %d == %d\n", bit_vector[1], bit_mask[1], results[1]);
results = simd_make_uint2(bit_vector | bit_mask);
printf("%d | %d == %d\t\t\t", bit_vector[0], bit_mask[0], results[0]);
printf("%d | %d == %d\n", bit_vector[1], bit_mask[1], results[1]);
results = simd_make_uint2(bit_vector ^ bit_mask);
printf("%d ^ %d == %d\t\t\t", bit_vector[0], bit_mask[0], results[0]);
printf("%d ^ %d == %d\n", bit_vector[1], bit_mask[1], results[1]);
}
@end
控制台输出: