下面的代码来自例子abo3.c来自不安全的编程 -也见为什么投extern puts给一个函数指针(void(*)(char*))&puts?:
int main(int argv,char **argc) {
extern system,puts;
void (*fn)(char*)=(void(*)(char*))&system; // <==
char buf[256];
fn=(void(*)(char*))&puts;
strcpy(buf,argc[1]);
fn(argc[2]);
exit(1);
}
Run Code Online (Sandbox Code Playgroud)
特别是这一行:
void (*fn)(char*)=(void(*)(char*))&system;
Run Code Online (Sandbox Code Playgroud)
我觉得这void (*fn)(char*)听起来像一个lambda,但我知道它不是.那么,也许这只是一个带括号的游戏,其中void *fn(char*)是一个函数的声明,这个函数正在引用system?但为什么(char*参数没有名字?这是允许的吗?
它将变量声明fn为函数指针(对于具有一个类型的参数char *且不返回任何内容的函数(void).
此变量初始化地址为system- 请参阅http://linux.die.net/man/3/system.如本页所述,这将需要演员表
void (*fn)(char*)=(void(*)(char*))&system;
Run Code Online (Sandbox Code Playgroud)
该行获取错误声明符号的地址system(应该是int(const char*),而不是隐式int),将其转换为 的类型fn并初始化该新的局部变量。
该类型是void(*)(char*)或指向接收单个值char*且不返回任何内容的函数的指针。
前两个参数的传统命名方式main相反:
int main(int argv,char **argc)
Run Code Online (Sandbox Code Playgroud)声明标准库函数system并puts使用“隐式 int”作为ints。这甚至不是错误的函数类型,而是数据类型!
extern system,puts;
Run Code Online (Sandbox Code Playgroud)将符号地址转换为函数指针几乎是明智的。现在只要它是正确的类型就好了……无论如何,在数据指针和代码指针大小相同的盒子上,它可能不会丢失任何信息。
void (*fn)(char*)=(void(*)(char*))&system; // <==
fn=(void(*)(char*))&puts;
Run Code Online (Sandbox Code Playgroud)检查argv[!] 是否至少为 2 确实不应该在这里省略:
strcpy(buf,argc[1]);
Run Code Online (Sandbox Code Playgroud)通过错误类型的函数指针调用函数是 UB。不要那样做。另外,检查argv[!] 在此之前是否至少为 3 也是可选的。fn(argc[2]);
依赖strcpyand的隐式声明exit也非常糟糕。两者都没有与之相符的原型!(他们没有回来int)