【问题标题】:Is it possible to hide a portion of a standard header (in C)?是否可以隐藏标准标题的一部分(在 C 中)?
【发布时间】:2014-02-10 20:07:33
【问题描述】:

我想做一些看似不可能的事情。

我要写 3 个文件:ma​​in.cfoo.hfoo.c
这个想法是在 foo.hfoo.c 中定义一个结构,使其成员在 ma​​in.c 中可见。其中一个结构成员的类型为FILE,如标准头<stdio.h> 中所定义。但是<stdio.h> 的函数和宏必须在文件 ma​​in.c 中保持不可见。

该解决方案必须符合标准 C(C99 和/或 C11)并且可移植。 这可能吗?

foo.h 标头在 ma​​in.cfoo.c 中都#included。
标准头 <stdio.h> 仅在 foo.c 中包含 #include,但在 ma​​in.c 中不包含。

我想声明一个struct如下:

struct myfile_s {
   FILE *F;
   char *filename;
   char buff[100];
} myfile;

对于接下来的内容,只有成员 FILE *F 很重要。
struct myfile 将被 foo.c 中出现的函数初始化和修改。
目的是通过 foo.h 中声明的 extern 函数对 myfile 进行文件操作,而这些函数又必须在 foo.c 中定义。 p>

文件操作涉及<stdio.h>的标准函数,但这些函数必须隐藏在文件ma​​in.c中。 但是,我想从 ma​​in.c 直接访问myfile 的成员。 这意味着struct myfile_s 的定义必须在foo.h 中完成(也就是说,它不能通过使用不完整结构声明的技巧来“延迟”,例如struct myfile_s ;)。

简而言之,我希望 FILE 类型在 ma​​in.c 和/或 foo.h 中可见,但其余的 <stdio.h> 声明为他们隐藏。

另一个限制:直接复制由<stdio.h> 提供的FILE 的定义的想法是不可取的,因为代码必须是可移植的。

我的第一次尝试是将 struct myfile 隐藏在 foo.c 中。
代码是:

foo.h

struct myfile_s;

struct myfile_s myfile;

extern void startfile(struct myfile *f);

foo.c

#include <stdio.h>
#include "foo.h"

struct myfile_s {
   FILE *F;
   char *filename;
   char buff[100];
} myfile;

void startfile(struct myfile *f) 
{
    // Do some stuff...
}

ma​​in.c

#include "foo.h"

int main(void) 
{
   myfile.F = NULL;  // This kind of access bring error, but I want to do it anyway!!
   startfile(&myfile);
   return 0;
}

延迟的struct myfile_s 声明避免了在foo.h 中包含&lt;stdio.h&gt; 的需要,因此标头工作正常,但结构类型仍然不完整,因此无法访问myfile.Fma​​in.c 中完成。

所以:如何访问 myfile.F?

我尝试了另一种方法,当然也会出错:

foo.h

struct myfile_s {
   FILE *F;
   char *filename;
   char buff[100];
} myfile;

extern void startfile(struct myfile *f);

foo.c

#include <stdio.h>
#include "foo.h"

void startfile(struct myfile *f) 
{
    // Do some stuff...
}

【问题讨论】:

  • 使用两个不同的标题还不够吗?一个内部头文件和一个外部?外部只知道 void 指针(或者在您的情况下是结构的 FILE 指针部分)和内部您将这些 void 指针转换为您的类型,因此具有内部头文件的人知道您要保留的部分内部和外部头 jsut 显示你想给什么。
  • 您是否尝试在foo.h 中包含&lt;stdio.h&gt;,即您定义结构的位置...我更喜欢在标题中声明它
  • 第二种方法有什么问题?它看起来大部分都在正确的轨道上。
  • @MichaelAaronSafyan:因为FILE 类型定义在&lt;stdio.h&gt; 中,它包含在foo.c 中但不在foo.h 中。这个想法是&lt;stdio.h&gt; 的功能必须在文件main.c 中不可见。
  • #define FILE void 添加到您的主目录。可能会有所帮助(但承认有点麻烦)。这当然是在包含 foo.h 之前

标签: c


【解决方案1】:
struct myfile_s {
   void *pPrivateThings; // This could be the FILE* or another private structure
   char *filename;
   char buff[100];
} myfile;

我会在创建时分配另一个私有结构:

struct myprivatefile_s {
    FILE *F;
    // You could add other fields here that are not public
} myprivatefile;

myprivatefile *privateThings = malloc(sizeof(myprivatefile));
myfile.pPrivateThings = privateThings;
privateThings->F = fopen(); 

这样您就可以继续将不需要可见(即私密)的内容添加到您心中的内容中。

【讨论】:

  • 看起来像 pimpl C++ 成语。只是,我要补充一点,您可以只声明 struct myprivatefile_s; 而无需在“公共”标头中定义它,并使用指针中的类型而不是 void*
  • 您使用myfile 作为“类型”,但它是struct myfile_s 类型的变量。然而,这是一个小错误。我已经尝试使用 void* 指针,它可以访问 myfile.F,但现在的问题是“实际”类型 FILE 不是“纯”(它不是真正的)。但是,根据我执行问题的方式,您给出了一个很好的答案。这不是我要找的,但你的答案是我最喜欢的,因为你给了我几个想法。
  • 感谢您指出错误。已更正它并展示了如何使用文件指针。
【解决方案2】:

这都是不必要的复杂,不是吗?

看起来好像你真的不知道自己想要什么。为什么要在foo.h 中有一个myfile 的实例?为什么要在main 中显式设置myfile.F?为什么不在foo.c 中写一个类似myfile_init 的函数,它具有完全访问权限?

我会在 foo.h 中对不透明结构进行 typedef,在 foo.h 中定义内容并实现构造函数和访问器函数,然后在 main.c 中创建 myfile 的实例:

foo.h

typedef struct Myfile Myfile;

Myfile *myfile_open(const char *filename);
myfile_process(Myfile *f, ...);
int myfile_close(Myfile *f);

foo.c

#include <stdio.h>

struct Myfile {
    FILE *f;
    ...
};

// implement myfile_xxx functions

ma​​in.c

#include "foo.h"

int main()
{
    Myfile *f = myfile_open("rhubarb.txt");

    if (f == NULL) exit(1);
    myfile_process(f, ...);
    myfile_close(f);

    return 0;
}

无需部分包含其他标题。通过将初始化移至myfile_open,所有内容都整齐地封装在foo.c 中。主程序只看到句柄。真的很像标准的FILE * 句柄。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-16
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多