99% , C89. . : , . , , . , , signal, , , .
- , , (, ).
, - setjmp longjmp, double jmp_buf.
-, , , . , , double z . , . .
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
double func(double x, double z)
{
printf("%g\n", z);
return x;
}
double bar(double x)
{
printf("y\n");
return x;
}
double call(double (*f)(double))
{
return f(0.0);
}
struct cDblDblRetDbl
{
double (*function)(double, double);
double a;
char code[1];
double pad;
};
static double helper(double x)
{
double *dp = (double *) helper;
struct cDblDblRetDbl *data;
dp += 2;
data = (struct cDblDblRetDbl *) dp;
--data;
return data->function(x, data->a);
}
#define CODE_SIZE 0x60
double (*curryDoubleDoubleReturningDouble(double (*function)(double, double), double a))(double)
{
size_t size = sizeof(struct cDblDblRetDbl) + CODE_SIZE;
struct cDblDblRetDbl *result = valloc(size);
result->function = function;
result->a = a;
memcpy(result->code, (void *) helper, CODE_SIZE);
mprotect(result, CODE_SIZE, PROT_READ | PROT_EXEC | PROT_WRITE);
return (double(*)(double)) result->code;
}
int main()
{
call(bar);
call(curryDoubleDoubleReturningDouble(func, 5));
call(curryDoubleDoubleReturningDouble(func, 7));
call(curryDoubleDoubleReturningDouble(func, 42.9));
}
If you wrote helperin the assembly and created versions curryDoubleDoubleReturningDoublefor the OS, you could probably get this to work a lot of places. But I'm sure there are several C computers on which you cannot do this.
source
share