请考虑以下代码:
交流电
#include <stdio.h>
#include "b.h"
static int a = 41;
static void test(void){
a++;
printf("a: %dn", a);
}
int main(void){
set_callback(test);
call();
return 0;
}
不列颠哥伦比亚省
static void (*callback)(void);
void set_callback(void (*func)(void)){
callback = func;
}
void call(void){
if (callback){
callback();
}
}
B.H
void set_callback(void (*func)(void));
void call(void);
这将在没有警告-Wall
的情况下进行编译,并按预期打印出a: 42
。
现在,这可能不是最佳实践,因为a.c
的编写者可能不希望从另一个文件调用test()
并且a
修改变量,但这是合法的 C 代码吗?它会在不同的平台和编译器上移植吗?
是的,这是非常好的代码,甚至是好的代码。您的test
回调不需要是全局的。
编译器负责确保不会在翻译单元外部调用函数,然后再执行任何会影响从外部调用函数的优化。
如果它看到指向函数的指针被传递给外部函数,则必须避免对函数进行不兼容的优化。
因此,唯一的效果是对象文件不会导出test
符号(这称为内部链接)。
你写道,
现在,这可能不是最佳实践,因为 a.c 的编写者可能不希望从另一个文件调用 test() 并且变量是修改的,但这是合法的 C 代码吗?
如果编写器不希望从另一个文件调用他的test()
函数,他不应该将指向它的指针传递给外部模块!
当编写者调用set_callback(test);
时,他知道他正在将静态方法传递给外部模块,并授予该外部模块调用它的权限。
关键是作者负责test
方法及其去向。 他没有被阻止做任何事情,但他可以控制他的数据的去向;他选择把它传给一个外人。