我99%肯定它是不可能用純C89。爲了做到這一點,你必須在運行時創建一個新的函數指針。有兩種獲取函數指針的方法:從函數表達式或從返回函數指針的標準庫函數中獲取函數指針。函數表達式是指在編譯時定義的函數,所以不起作用。它返回一個函數指針的唯一標準庫函數是signal
,這是沒有任何幫助,因爲你只把它弄出來你把豆。
唯一的其他方式來獲得一個新的函數指針將指向轉換爲一個對象類型轉換爲一個函數指針,並且這不是可移植的,因爲它不在可以執行的指針轉換列表中(不過,它被記錄爲一個通用擴展)。
一小會兒我想你也許能setjmp
和longjmp
得到的地方,但只是替換存儲jmp_buf
的問題存儲double
的問題。
我確實得到了今天在我的系統上正常工作的事情,但由於它不可移植,即使升級我的編譯器也可能會破壞它。總體思路是創建一個結構,其中包含指向原始函數的指針double z
以及一些訪問該信息並調用原始代碼的機器代碼。我不建議你使用這個,但我覺得它很有趣。我已經在評論中指出了一些不可移植的假設。
/* platform-specific include */
#include <sys/mman.h>
/* standard includes */
#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)
{
/* Casting a function pointer to an object pointer is
* not provided by the standard.
* In addition, this only works because the compiler
* happens to use RIP-relative addressing, so "helper"
* points to the beginning of the currently executing
* function, which is actually a copy of the one in
* the object file.
* It's worth noting explicitly that nothing in the
* C standard says that a pointer to a function will
* point to its machine code.
*/
double *dp = (double *) helper;
struct cDblDblRetDbl *data;
/* Modify it to point after the structure.
* This depends on the alignment and padding of the
* structure, which is not portable.
*/
dp += 2;
data = (struct cDblDblRetDbl *) dp;
/* back it up to the structure */
--data;
/* now call the function with the saved data. */
return data->function(x, data->a);
}
/* There is no way to get the code size of a function,
* so this is very nonportable.
* I found it by examining the object file.
*/
#define CODE_SIZE 0x60
double (*curryDoubleDoubleReturningDouble(double (*function)(double, double), double a))(double)
{
size_t size = sizeof(struct cDblDblRetDbl) + CODE_SIZE;
/* valloc is nonstandard but we need an area aligned to a
* page boundary for mprotect.
*/
struct cDblDblRetDbl *result = valloc(size);
result->function = function;
result->a = a;
/* Copy the code of the helper function into the structure.
* Once again, we're casting a function pointer to an
* object pointer and the standard doesn't say you can do that.
*/
memcpy(result->code, (void *) helper, CODE_SIZE);
/* Memory protection is out of the scope of the standard,
* and in a real program we need to check the return value.
*/
mprotect(result, CODE_SIZE, PROT_READ | PROT_EXEC | PROT_WRITE);
/* Casting an object pointer to a function pointer is also
* not provided by the standard.
* This example leaks memory.
*/
return (double(*)(double)) result->code;
}
int main()
{
call(bar);
call(curryDoubleDoubleReturningDouble(func, 5));
call(curryDoubleDoubleReturningDouble(func, 7));
call(curryDoubleDoubleReturningDouble(func, 42.9));
}
如果你寫了裝配helper
,創造了curryDoubleDoubleReturningDouble
操作系統特定版本中,你很可能得到這個工作了很多地方。但是我確信有一些電腦C運行在你無法做到的地方。
沒有ISO C98。最初的標準是ANSI C89;它作爲ISO C90被採用,沒有顯着變化。後來的標準是ISO C99和ISO C11。 –
任何事情,你可以做一個全球性的,你可以做到沒有全球... –
@KeithThompson是的,我的意思是C99。我寫這個時可能考慮過C++ 98。 –