我能以某种方式在 ANSI C 中使用嵌套函数吗?
Can I somehow use nested functions in ANSI C?
我有高级语言背景,例如Java/Kotlin/Scala。现在我需要创建一个 C 库,但没有闭包对我来说很难工作。
GCC 中有一个很好的扩展,称为 "nested functions",(如果我理解正确的话)正是我所需要的。 Apple "blocks" 扩展看起来也很有趣。但我需要一个适用于任何编译器的代码。
有现成的解决方案吗?我见过一些允许生成 C 代码的项目:https://github.com/dbohdan/compilers-targeting-c。但我真的不需要另一种语言,只需要一个特性——闭包。 (我认为很难维护完全不同的语言,结果C代码不会优化)。
UPD
一些解释,为什么我需要闭包。
假设我们有一些功能,connect(void (*on_failed_callback)());
。它以某种方式管理连接,当连接丢失时,它调用回调。它需要 0 个参数,但我想创建一些函数来带回一些数据。如果我理解正确的话,最常用的解决方案是使用一些参数 connect(void (*on_failed_callback)(void *callback_arg), void* arg);
传递回调。但它会导致样板代码,可以通过嵌套函数修复。
所以下一个代码:
void connect(void (*on_failed_callback)(void* arg), void* arg) {
...
on_failed_callback(arg);
}
void print_error(char* error) {
printf(error);
}
void main() {
char *msg = "Failed connection";
...
connect(print_error, msg);
}
可以简化为下一个:
void connect(void (*on_failed_callback)()) {
...
on_failed_callback();
}
void print_error(char* error) {
printf(error);
}
void main() {
char* msg = "Failed connection";
...
void callback() {
print_error(msg);
}
connect(callback);
}
我的意思是,我想要一些 tool/app,用 closures/nested 函数分析我的代码并生成纯 ANSI C 代码。
对于您询问的具体示例,有一种 C 方法实现了类似于闭包的功能,因为它将函数指针与函数需要使用的数据打包在一起。
typedef struct {
char sBuff[128]; // data for the function to use
void (* func) (char* error); // pointer to function to execute
} ErrorMsg;
void connect(ErrorMsg myMsg) {
...
myMsg.func(myMsg.sBuff); // call the function with the packaged data
}
// the function that we will be encapsulating with the data to be
// used.
void print_error(char* error) {
printf(error);
}
void main() {
ErrorMsg msg = {"Failed connection", print_error} ;
…
connect(msg); // invoke our function package and its data.
}
如果在使用功能包的时候,你还想添加额外的数据,可以按照下面的方式进行。
typedef struct {
char sBuff[128]; // packaged data for the function to use
void (* func) (char* error, int iExtra); // pointer to function to execute
} ErrorMsg;
void connect(ErrorMsg myMsg) {
...
myMsg.func(myMsg.sBuff, errno); // call the function with the packaged data and extra info
}
// the function that we will be encapsulating with the data to be
// used.
void print_error(char* error, int iExtra) {
printf(error, iExtra);
}
void main() {
ErrorMsg msg = {"Failed connection: errno %d", print_error} ;
…
connect(msg); // invoke our function package and its data.
}
Does any existing solution present?
这取决于你的意思。标准 C 不提供闭包、嵌套函数或 lambdas / 块作为语言特性。但是,如果没有 C 语言中的任何或所有这些功能,您就无法使用其他语言来做任何事情。事实上,一些 具有这些特性的语言本身就是用 C 语言实现的。
特别是,您的第一个示例大致是通用回调的正常 C 习惯用法。回调函数接受一个指向包含它需要的任何数据的对象的指针,并且 callback-registration 接口接受一个指向适当对象的指针以及一个指向函数的指针。当触发回调时,将注册的数据指针传递给它。
请注意,顺便说一下,这是一个比闭包单独提供的更通用的工具,因为回调将操作的数据不需要在函数定义的范围内。除其他外,这允许提供标准的、可重用的回调实现,其中与特定数据的关联仅在回调注册时进行。如果多个回调可以同时与同一个事件相关联,它还允许对同一个事件重复使用具有不同数据的同一个回调。
我有高级语言背景,例如Java/Kotlin/Scala。现在我需要创建一个 C 库,但没有闭包对我来说很难工作。
GCC 中有一个很好的扩展,称为 "nested functions",(如果我理解正确的话)正是我所需要的。 Apple "blocks" 扩展看起来也很有趣。但我需要一个适用于任何编译器的代码。
有现成的解决方案吗?我见过一些允许生成 C 代码的项目:https://github.com/dbohdan/compilers-targeting-c。但我真的不需要另一种语言,只需要一个特性——闭包。 (我认为很难维护完全不同的语言,结果C代码不会优化)。
UPD 一些解释,为什么我需要闭包。
假设我们有一些功能,connect(void (*on_failed_callback)());
。它以某种方式管理连接,当连接丢失时,它调用回调。它需要 0 个参数,但我想创建一些函数来带回一些数据。如果我理解正确的话,最常用的解决方案是使用一些参数 connect(void (*on_failed_callback)(void *callback_arg), void* arg);
传递回调。但它会导致样板代码,可以通过嵌套函数修复。
所以下一个代码:
void connect(void (*on_failed_callback)(void* arg), void* arg) {
...
on_failed_callback(arg);
}
void print_error(char* error) {
printf(error);
}
void main() {
char *msg = "Failed connection";
...
connect(print_error, msg);
}
可以简化为下一个:
void connect(void (*on_failed_callback)()) {
...
on_failed_callback();
}
void print_error(char* error) {
printf(error);
}
void main() {
char* msg = "Failed connection";
...
void callback() {
print_error(msg);
}
connect(callback);
}
我的意思是,我想要一些 tool/app,用 closures/nested 函数分析我的代码并生成纯 ANSI C 代码。
对于您询问的具体示例,有一种 C 方法实现了类似于闭包的功能,因为它将函数指针与函数需要使用的数据打包在一起。
typedef struct {
char sBuff[128]; // data for the function to use
void (* func) (char* error); // pointer to function to execute
} ErrorMsg;
void connect(ErrorMsg myMsg) {
...
myMsg.func(myMsg.sBuff); // call the function with the packaged data
}
// the function that we will be encapsulating with the data to be
// used.
void print_error(char* error) {
printf(error);
}
void main() {
ErrorMsg msg = {"Failed connection", print_error} ;
…
connect(msg); // invoke our function package and its data.
}
如果在使用功能包的时候,你还想添加额外的数据,可以按照下面的方式进行。
typedef struct {
char sBuff[128]; // packaged data for the function to use
void (* func) (char* error, int iExtra); // pointer to function to execute
} ErrorMsg;
void connect(ErrorMsg myMsg) {
...
myMsg.func(myMsg.sBuff, errno); // call the function with the packaged data and extra info
}
// the function that we will be encapsulating with the data to be
// used.
void print_error(char* error, int iExtra) {
printf(error, iExtra);
}
void main() {
ErrorMsg msg = {"Failed connection: errno %d", print_error} ;
…
connect(msg); // invoke our function package and its data.
}
Does any existing solution present?
这取决于你的意思。标准 C 不提供闭包、嵌套函数或 lambdas / 块作为语言特性。但是,如果没有 C 语言中的任何或所有这些功能,您就无法使用其他语言来做任何事情。事实上,一些 具有这些特性的语言本身就是用 C 语言实现的。
特别是,您的第一个示例大致是通用回调的正常 C 习惯用法。回调函数接受一个指向包含它需要的任何数据的对象的指针,并且 callback-registration 接口接受一个指向适当对象的指针以及一个指向函数的指针。当触发回调时,将注册的数据指针传递给它。
请注意,顺便说一下,这是一个比闭包单独提供的更通用的工具,因为回调将操作的数据不需要在函数定义的范围内。除其他外,这允许提供标准的、可重用的回调实现,其中与特定数据的关联仅在回调注册时进行。如果多个回调可以同时与同一个事件相关联,它还允许对同一个事件重复使用具有不同数据的同一个回调。