【问题标题】:Is it possible to store function arguments in a pointer to function?是否可以将函数参数存储在指向函数的指针中?
【发布时间】:2019-05-04 13:53:32
【问题描述】:

出于好奇,我试图了解指向函数的指针在 C 中是如何工作的。

为了将函数与 typedef 关联,我在其中声明了一个指针,然后将所需函数的地址存储在其中。

这是我能够实现的:

typedef struct
{

    void (*get)(char*, int);
    char string[10];

} password;

int main()
{
    password userPassword;

    userPassword.get = &hiddenStringInput; 

    userPassword.get(userPassword.string, 10);

    return EXIT_SUCCESS;
}

虽然这实际上工作得很好,但我希望“userPassword.get”成为一个快捷方式,在使用时调用 hiddenStringInput 函数并填写请求的参数(在这种情况下,一个字符数组和一个整数) .

基本上,由于我总是将 userPassword.get 与参数“userPassword.string”和“10”一起使用,因此我试图找出一种方法以某种方式将这些参数存储在指向的指针中到 hiddenString 函数。有可能吗?

【问题讨论】:

  • 如果您迁移到 C++,您可以使用 lambda 函数或函数对象来实现这一点。毫无疑问,C 有技巧,但这超出了我的工资等级。
  • There's been a soft push to integrate this into C for some time,但该功能尚未以标准化的一流方式存在。它可能会包含在 C2x(下一个标准修订版)中如果比只有 Clang 支持它的编译器更多。我正在努力。
  • 如果我理解正确的话,你基本上想要成员函数。这就是(一个原因)为什么会有 C++。

标签: c


【解决方案1】:

我认为这通常是通过提供一个“调度”函数来完成的:

void get(password * pw) {
  pw->get(pw->string, 10);
}

然后,将userPassword.get 设置为您的函数后,您只需调用:

get(userPassword);

显然,当为多个功能完成时,这会添加一些样板代码。不过,允许实现更多有趣的“类”事物。

【讨论】:

  • 几乎像一个 lambda
  • 好建议,但如果它明确回答是否可以以某种方式将参数存储在函数指针本身中的问题,这将是一个更好的答案。
【解决方案2】:

您可以使用“块”语言扩展在 Clang 中执行此操作。正如所评论的那样,there have been attempts to standardize this(并没有收到任何敌意或任何东西),但他们进展缓慢。

转换为使用 Blocks,您的示例可能如下所示:

#include <stdlib.h>

#include <Block.h>

typedef void (^GetPw)(int);             // notice how Block pointer types are used
typedef void (*GetPw_Impl)(char*, int); // the same way as function pointer types

typedef struct
{
    GetPw get;
    char string[10];
} password;

extern void hiddenStringInput(char*, int);

extern void setPw(char dst [static 10], char * src);

GetPw bindPw (GetPw_Impl get_impl, char * pw)
{
  return Block_copy (^ (int key) {
    get_impl (pw, key);
  });
}

int main()
{
    password userPassword;

    setPw(userPassword.string, "secret");

    userPassword.get = bindPw(hiddenStringInput, userPassword.string); 

    userPassword.get(10);

    return EXIT_SUCCESS;
}

捕获数组的方式有一些微妙之处,可能会混淆这种情况;该示例通过普通指针捕获密码并假定userPassword 负责它的所有权,与块分开。

由于块捕获值,它需要为捕获值的副本提供和释放动态存储,当块本身被复制到创建它的范围之外时,这些副本将被创建;这是通过Block_copyBlock_release 函数完成的。

块类型(语法上是函数指针,但使用^而不是*)是只是指针——没有办法访问底层块实体,就像基本的C函数一样。 p>


这是 Clang API - 标准化会稍微改变这一点,并且可能会减少动态内存分配以复制块的需求(但 Clang API 反映了这些当前最常用的方式)。

【讨论】:

  • @Bathsheba 我对 C++ 不熟悉,但我或多或少已经知道用它来实现这种事情要容易得多,因为 C++ 是面向对象的。为了告诉你完整的故事,我试图这样做是为了尝试在 C 中模拟其他语言的类对象结构。我什至不确定它是否有用,但我真的很好奇知道它是否可以完成以及如何完成。在寻找这个问题的解决方案时,我偶然发现了一篇文章,其中提到 C++ 通过使用函数指针来实现面向对象的特性,学习起来非常有趣。
  • @Gian 有一个经典的 PDF Object Oriented C 可能感兴趣?您想要的可以完成,但有一百万或两种方法!例如12,如果只是因为有上百万种不同风格的 OOP 可以复制。
  • 这看起来可能是一个非常有趣的阅读!感谢您提供此信息。
【解决方案3】:

所以,我刚刚意识到我可以直接在结构内部编写函数

typedef struct
{

    char string[10];

    void get(void)
    {
        hiddenStringInput(string, 10);

        return;
    }

    void set(const char* newPassword)
    {
        strcpy(string, newPassword);

        return;
    }

    void show(void)
    {
        printf("%s", string);

        return;
    }



} password;

现在我可以调用 userPassword.get()、userPassword.show() 和 userPassword.set("something"),而发生的事情正是标签所说的。有什么理由我不应该这样做吗?这看起来很方便。

编辑:所以这只能在 C++ 中实现。我没有意识到我正在使用 C++ 编译器,并且通过尝试做一些随机的事情,我想出了这个解决方案。所以这不是我真正想要的。

【讨论】:

  • 这是 C++,不是 C
  • 没有。这不是有效的 C。您可能正在使用 C++ 编译器,这就是它起作用的原因。
  • 好吧,这个很有道理,其实哈哈。对于这个错误,我很抱歉,我对此很陌生。
猜你喜欢
  • 2021-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-21
  • 1970-01-01
  • 1970-01-01
  • 2022-10-01
相关资源
最近更新 更多