澄清C中的函数指针

gui*_*015 12 c

下面的代码来自例子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*参数没有名字?这是允许的吗?

Ed *_*eal 8

它将变量声明fn为函数指针(对于具有一个类型的参数char *且不返回任何内容的函数(void).

此变量初始化地址为system- 请参阅http://linux.die.net/man/3/system.如本页所述,这将需要演员表


Ded*_*tor 2

void (*fn)(char*)=(void(*)(char*))&system;
Run Code Online (Sandbox Code Playgroud)

该行获取错误声明符号的地址system(应该是int(const char*),而不是隐式int),将其转换为 的类型fn并初始化该新的局部变量。
该类型是void(*)(char*)或指向接收单个值char*且不返回任何内容的函数的指针。


嗯,这段代码很糟糕

  1. 前两个参数的传统命名方式main相反:

    int main(int argv,char **argc)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 声明标准库函数systemputs使用“隐式 int”作为ints。这甚至不是错误的函数类型,而是数据类型!

    extern system,puts;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 将符号地址转换为函数指针几乎是明智的。现在只要它是正确的类型就好了……无论如何,在数据指针和代码指针大小相同的盒子上,它可能不会丢失任何信息。

    void (*fn)(char*)=(void(*)(char*))&system; // <==
    fn=(void(*)(char*))&puts;
    
    Run Code Online (Sandbox Code Playgroud)
  4. 检查argv[!] 是否至少为 2 确实应该在这里省略:

    strcpy(buf,argc[1]);
    
    Run Code Online (Sandbox Code Playgroud)
  5. 通过错误类型的函数指针调用函数是 UB。不要那样做。另外,检查argv[!] 在此之前是否至少为 3 也是可选的。fn(argc[2]);

  6. 依赖strcpyand的隐式声明exit也非常糟糕。两者都没有与之相符的原型!(他们没有回来int