0

如果需要,我可以提供具体的实施细节,但一般问题如下:

是否可以在头文件.h 中声明具有未知类型参数的函数,该参数仅在 file.c 中指定?

c++Template-like 解决方案不能解决我的情况,因为我不希望不同的参数类型可能作为我的函数的输入,定义只考虑一种情况,我宁愿没有这个选项。我只是想让header中的声明忽略参数类型,而只是通知其他文件这个函数的存在。这是可行的还是我应该重新考虑我的问题?

实现细节:该函数在 file.c 中声明为静态,我想通过包含相关的 file.h 标头来删除静态以便能够在其他地方使用它。

4

5 回答 5

3

你的评论:

也许实施细节会提供更多见解。我正在研究https://github.com/bitcoin-core/secp256k1,试图将静态函数变为 static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey)非静态函数并将其声明为具有相同名称的头文件,而不移动与参数类型相关的所有必需的包含。

这是有问题的,因为在引用的代码库中,typedef 命名别名匿名结构(typedef struct { ... } secp256k1_context;等)。

如果他们为标记结构(typedef struct tag typedef_name;typedef struct tag {...} typedef_name;)起别名,您可以简单地执行以下操作:

//forward-declare the structs (assuming tag = typedef_name)
struct secp256k1_context;
struct secp256k1_ge;
struct secp256k1_pubkey;
//use struct tag instead of typedef_name
int secp256k1_pubkey_load(const struct secp256k1_context* ctx, 
                          struct secp256k1_ge* ge, 
                          const struct secp256k1_pubkey* pubkey);

但事实并非如此,因此您确实需要包含参数类型的定义。(正如莫斯科的 Vlad所提到的,在这种特殊情况下,您可以使用无原型声明,但随后会失去类型安全性。)

这是一个很好的例子,说明为什么typedef将匿名聚合作为 API 的一部分是一个坏主意。

最好将 s 保留struct为 API 的一部分,或者将typedefs 用于可预测标记的结构,例如typedef struct file_tp file_tp;(如果stdio.h这样做,我们不必#include <stdio.h>每次我们只想传递一个文件指针,但它会呈现一个 non-forward-declarable FILEstdio.h即使在可以避免的情况下也需要包含。)

于 2020-01-10T15:29:46.630 回答
1

是的,你可以这样做。只需声明没有参数列表的函数。

例如

int my_function();

来自 C 标准(6.7.6.3 函数声明符(包括原型))

3 函数声明器中不属于该函数定义的标识符列表应为空。

  1. …函数声明器中的空列表不属于该函数定义的一部分,它指定不提供有关参数数量或类型的信息。

考虑到在这种情况下,您将有一些限制,例如默认参数 Promotions

另外,也许您还应该考虑使用通用选择作为替代方案。

于 2020-01-10T13:30:55.433 回答
0

声明函数原型的唯一原因是让其他代码接受什么参数,函数返回什么类型。所以你的想法(IMO)没有任何意义

于 2020-01-10T13:30:59.847 回答
0
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge,
                                 const secp256k1_pubkey* pubkey)

由于您只处理指向结构的指针,因此您只需要 typedef 和不完整的结构定义,您可以从定义它们的 .h 文件中获取它们,以便为编译器提供足够的声明上下文。这对于结构的 typedef 来说很容易,例如将这一行放在函数声明的上方:

typedef struct secp256k1_context_struct secp256k1_context;

进行相同的重新声明是安全的,因此无论有没有完整的标题都可以正常工作。

其他两种类型更成问题,因为它们是匿名结构的 typedef。我认为最好的方法是如果我们没有真实的声明,就给它一个虚假的声明,例如

#ifndef SECP256K1_H
typedef void secp256k1_pubkey;
#endif

#ifndef SECP256K1_GROUP_H
typedef void secp256k1_ge;
#endif

(您可以使用真正的 secp256k1_pubkey 定义,但 _ge 取决于可能变化的字段,我想有足够的上下文来选择正确的字段是您首先要避免的。)

尽管对库的更改,这有点脆弱,并且需要您在此文件之前包含 secp256k1 标头(如果有的话)。(否则你会得到编译器错误:在评论中记下你所做的事情,这样如果将来有人发现这个问题,他们就会知道如何修复它。)

然后,您可以在自己的标头中为函数定义提供足够的上下文。请注意,任何不只是从其他地方传递这些结构的调用代码无论如何都可能需要完整的结构定义:为什么不把这个函数声明放在一个新的 .h 中,无论如何都需要包含完整的头文件,只有一个几个具体的地方需要?

于 2020-01-10T14:02:34.127 回答
-2

您可以使用不带参数的函数:
int my_function() ; 或
带有 void * 参数的函数定义
int my_function(void *p1, void *p2 ...) ;

Sangeeth Saravanaraj 的评论

这是一个好主意吗?当然没有。

于 2020-01-10T13:46:50.307 回答