【问题标题】:Errors when using pointers to static functions in C / C ++在 C/C++ 中使用指向静态函数的指针时出错
【发布时间】:2021-08-19 10:38:28
【问题描述】:

我正在用 g++ 编译一个应用程序,该应用程序调用“C”库中定义的一些函数。 我需要调用的一些函数在原始“.c”文件中被定义为静态(我知道当一个函数被定义为静态时,它不会从该文件外部调用,但尽管如此,我需要从外部调用它们)。

我将使用指向函数的指针从该文件外部执行它们并查看它们如何工作,我准备了这个示例,我想在 file_2.c 中执行 file_1.c 中定义的静态函数 fun5 和 fun6

file_1.h
--------
#ifndef FILE_1_H
#define FILE_1_H

int (*getPtrFun6(void*))(int,char,char*);

#endif
file_1.c
--------
#include <stdio.h>

int(*ptr_fun5)(int,int);

static int fun5(int p1, int p2)
{
  printf("fun5 called.\n");
  ptr_fun5 = &fun5;

  return p1 + p2;
}

static int fun6(int p1, char p2, char* p3)
{
  printf("fun6 called with p1 = %d, p2 = %c, p3 = %s.\n", p1, p2, p3);
  return p1;
}

int (*getPtrFun6(void*))(int,char,char*)
{
  return fun6;
}
file_2.c
--------
#include <stdio.h>
#include <cstring>
#include "file_1.h"

extern int(*ptr_fun5)(int,int);
extern int(*ptr_fun6)(int,char,char*);

int main(void)
{
  int returnValue = 0;

  // To run fun5
  returnValue = (ptr_fun5)(15, 32);
  printf ("Returns %d\n", returnValue);

  // To run fun6
  char myString[50];
  memset(myString,0,50);
  strncpy(myString,"THIS IS OK",10);
  ptr_fun6 = getPtrFun6();  
  returnValue = (ptr_fun6)(32, 'v', myString);
  printf ("Returns %d\n", returnValue);

  return 0;  
}

我用命令编译程序:

g++ file_2.c file_1.c -o static_example

从源代码中可以看出,我尝试了两种不同的方式来使用指向静态函数的指针。

如果我在源代码中对 fun6 的所有内容发表评论,编译并运行它(只需调用 fun5)我会收到错误“分段错误”。

另一方面,如果我在源代码中对所有与 fun5 相关的内容进行注释并只留下 fun6,则在编译程序时会出现以下错误:

file_2.c: In function ‘int main()’:
file_2.c:20:25: error: too few arguments to function ‘int (* getPtrFun6(void*))(int, char, char*)’
   ptr_fun6 = getPtrFun6();
                         ^
In file included from file_2.c:4:
file_1.h:4:7: note: declared here
 int (*getPtrFun6(void*))(int,char,char*);
       ^~~~~~~~~~

我查看了网络上的各种论坛和教程,但我没有看到错误是什么,所以我需要一些帮助来正确使用指向 fun5 和 fun6 的指针。

【问题讨论】:

  • 当您使用调试器一步一步地运行程序时,一次一行,您的调试器向您展示了什么?
  • 如果一个函数是静态的,那么它并不意味着从任何其他编译单元调用。它是该文件的本地文件。如果您需要在其他编译单元中调用该函数,您只需删除 static 关键字并使其具有外部链接即可。这整个指针业务看起来很可怕
  • 这有点太宽泛了,@MoNazemi。允许通过函数指针从不同的编译单元调用静态函数,并且它有一些合理的用例。当然这不是一个普通人应该做的,但static 在技术上是关于函数标识符的链接,并且只是间接地关于从哪里可以调用它。
  • @MoNazemi 在这种情况下,是的,全局变量是非常糟糕的设计。但一般来说,在某些情况下,将函数指针返回到内部实现是一个好主意。这是私有封装的一种方式。
  • 顺便说一句,从#include &lt;cstring&gt; 来看,您似乎将这些文件编译为 C++。如果您有一个正确支持 C 的编译器,您可能希望将其更改为 #include &lt;string.h&gt; 并确保您的编译器编译为 C,而不是 C++。两种语言之间存在差异,将 C 源代码编译为 C++ 会在学习时造成混淆。

标签: c++ c static function-pointers


【解决方案1】:

(只需调用 fun5)我收到错误“分段错误”。

因为 fun5 未初始化,所以它不指向任何地方。

编译程序时,出现以下错误:...错误:函数参数太少

那么你为什么要声明它以void* 作为参数呢?如果你不想这样,那么它应该是void


一般建议:

  • 用 extern 去掉全局变量。
  • 在处理函数指针时使用 typedef,以便人类可以阅读代码。显然,int (*getPtrFun6(void*))(int,char,char*) 连您自己都无法阅读。

【讨论】:

    【解决方案2】:
    int (*getPtrFun6(void*))(int,char,char*);
    

    混乱的语法导致错误的原型和声明。

    易于阅读的方式(函数指针与“普通”指针相同):

    typedef int fun6type(int, char, char *);
    
    fun6type *getPtrFun6(void);
    
    fun6type *getPtrFun6(void)
    {
      return fun6;
    }
    

    难以阅读的方式:

    int (*getPtrFun6_1(void))(int, char, char *);
    
    int (*getPtrFun6_1(void))(int, char, char *)
    {
        return fun6;
    }
    
    int foo(void)
    {
        int (*f)(int, char, char *) = getPtrFun6_1();
    
        return f(1, 'a', "Test");
    }
    

    自己测试一下 https://godbolt.org/z/erh63jTc8

    如果我在源代码中评论了关于 fun6 的所有内容,请编译它 并运行它(只需调用 fun5)我收到错误“分段错误”。

    函数指针必须在像任何其他指针一样被取消引用(调用)之前引用一个有效的函数。你的没有初始化,它没有引用一个有效的函数。

    顺便说一句,它是 C 代码(不是 C++)。在 C++ 中应避免使用函数指针(通常是指针)。

    【讨论】:

      【解决方案3】:

      returnValue = (ptr_fun5)(15, 32); 不起作用,因为 ptr_fun5 被初始化为空指针,并且在执行 fun5 内的语句 ptr_fun5 = &amp;fun5; 之前不会被赋予任何其他值,直到调用 fun5 才会发生。

      解决此问题的一种方法是删除int(*ptr_fun5)(int,int); 并将int (*ptr_fun5)(int, int) = fun5; 放在fun5 的声明之后。然后初始化为fun5的地址。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-21
        • 2018-01-02
        • 1970-01-01
        • 2012-05-05
        • 1970-01-01
        • 1970-01-01
        • 2020-08-04
        相关资源
        最近更新 更多