gpt4 book ai didi

c - 有一个没有定义的结构是什么意思?

转载 作者:太空狗 更新时间:2023-10-29 15:01:38 25 4
gpt4 key购买 nike

最近,我在我的系统中遇到了以下代码 stdio.h :

struct _IO_FILE_plus;
extern struct _IO_FILE_plus _IO_2_1_stdin_;
extern struct _IO_FILE_plus _IO_2_1_stdout_;
extern struct _IO_FILE_plus _IO_2_1_stderr_;

我习惯于看到指向像这样前向声明的结构的指针: extern struct _IO_FILE *stdin; ,但是拥有一个裸结构似乎很奇怪,因为您不能使用该结构或将其传递给函数。这只是一个空操作吗?

最佳答案

代码struct _IO_FILE_plus;是名称 _IO_FILE_plus 的声明这样如果编译器看到它在某个地方被使用,它就会知道在某个点会有一个实际描述其成员的定义。
extern修饰符表示命名的符号是存在于其他编译单元中的外部符号。代码如:

extern struct _IO_FILE_plus _IO_2_1_stdin_;

也是符号的声明,在本例中 _IO_2_1_stdin_ ,告诉编译器该符号是定义并存在于某个其他编译单元(文件)中的外部符号以及该符号的类型是什么,在本例中为 struct _IO_FILE_plus .

但是通常使用 struct其他声明中的声明通常会使用指向 struct 的指针。自 struct的大小并且它的布局不能仅仅通过诸如 struct _IO_FILE_plus; 的声明来确定。 .

但是在这种情况下因为它是外部的,除非源代码包含一些要求 struct 的大小和布局的声明。可供编译器使用,以这种方式使用声明的符号。

所以如果你有这样的消息来源:
struct _IO_FILE_plus *myIo = malloc(sizeof(struct _IO_FILE_plus));

struct _IO_FILE_plus myIo = _IO_2_1_stdin_; // no pointers here, struct assignment

这些会产生错误,因为编译器需要定义 struct _IO_FILE_plus以确定 sizeof()的结果或为 struct 复制的内存量这些语句中的赋值。

但是,如果您有以下声明:
struct _IO_FILE_plus *myIO = &_IO_2_1_stdin_;

这将编译,因为编译器只需要知道如何找到外部变量的地址并将该地址放入指针变量中。当应用程序被加载并设置为运行时,外部变量的地址由加载器固定。

如果外部不存在,那么在链接时您将收到“未解析的外部符号”错误。

API 库示例

这可能很有用的一种方式是,如果您有几个不同的对象或设备由代理对象表示,并且您有一个函数库,您希望允许人们为其中的函数选择目标对象或设备。

因此,您要做的是在您的库中将这些对象或代理对象公开为外部对象,但仅通过提供声明来保密它们的内部信息。

然后在函数接口(interface)中,您需要一个指向与函数一起使用的适当对象或代理对象的指针。

这种方法的好处在于,可以访问您的库内部结构的其他方可以提供与您的库一起使用的其他代理对象,但使用他们自己的代理对象。

这在 struct 时特别有效定义包含指向钩子(Hook)函数的指针,您的库将调用这些函数来执行第三方知道但您不必知道的特定于设备的操作。钩子(Hook)函数有一个带有一组预期结果的定义接口(interface),如何完成取决于钩子(Hook)函数的提供者。

所以库源文件:
struct _IO_FILE_plus {
unsigned char buffer[1024];
int bufptr1;
// … other struct member definitions
int (*hookOne)(struct _IO_FILE_plus *obj); // third party hook function pointer
int (*hookTwo)(struct _IO_FILE_plus *obj); // third party hook function pointer
};

struct _IO_FILE_plus _IO_2_1_stdin_ = { {0}, 0, …. };
struct _IO_FILE_plus _IO_2_1_stdout_ = { {0}, 0, …. };
struct _IO_FILE_plus _IO_2_1_stderr_ = { {0}, 0, …. };

int funcOne (struct _IO_FILE_plus *obj, int aThing)
{
int iResult;

if (obj->hookOne) iResult = obj->hookOne(obj);

// do other funcOne() stuff using the object, obj, provided

return iResult;
}


int funcTwo (struct _IO_FILE_plus *obj, double aThing)
{
int iResult;

if (obj->hookTwo) iResult = obj->hookTwo(obj);

// do other funcTwo() stuff using the object, obj, provided

return iResult;
}

库源文件编译良好,因为编译器具有 struct 的完整定义可用的。然后在与库一起提供的头文件中,您有以下语句:
struct _IO_FILE_plus ;

extern struct _IO_FILE_plus _IO_2_1_stdin_ ;
extern struct _IO_FILE_plus _IO_2_1_stdout_ ;
extern struct _IO_FILE_plus _IO_2_1_stderr_ ;

extern int funcOne (struct _IO_FILE_plus *obj, int aThing);
extern int funcTwo (struct _IO_FILE_plus *obj, double aThing);

这些都有效,因为这些源语句都不需要 struct 的实际定义。可供编译器使用。编译器只需要知道在某处定义了这样的符号。

在使用这些的源文件中,您可以有如下语句:
int k = funcOne(&_IO_2_1_stdin_, 5);

同样,这仅需要编译器知道该符号存在,并且在某个时候该符号的地址将可用。

作为库设计的一部分,很可能会使用 C 预处理器宏来进一步隐藏其中的一些管道。所以你可能有宏,例如:
#define DO_FUNCONE(io,iVal)  funcOne(&(io), (iVal))

#define DO_FUNCONE_STDIN(iVal) funcOne(&_IO_2_1_stdin_,(iVal))

#define IO_STDIN (&_IO_2_1_stdin)

然而,像下面这样的语句不会编译,因为编译器将提供 struct 的副本。到采用外部值而不是指向它的指针的函数:
int k = doFuncOne (_IO_2_1_stdin_);  // compiler error. definition of struct _IO_FILE_plus not available

其中函数的函数定义 doFuncOne()好像:
// compiler error. definition of struct _IO_FILE_plus not available
int doFuncOne (struct _IO_FILE_plus obj) // notice this is struct and not pointer to struct
{
// do some setup then call funcOne().
return funcOne(&obj, 33);
}

然而功能界面的改变 doFuncOne()将允许它编译:
// following would compile as only declaration is needed by the compiler.
int doFuncOne (struct _IO_FILE_plus *obj) // notice this is now pointer to struct
{
// do some setup then call funcOne().
return funcOne(obj, 33);
}

该库可以提供一个版本的函数 funcOne() ,说 funcOneStruct() ,它允许 struct 的参数而不是指向 struct 的指针因为编译器有 struct 的定义编译库的源文件时可用。然而,使用该库的人将无法使用该函数,因为该库的用户只有 struct 的声明。对他们可用,而不是 struct 的定义.

这样的函数可能对定义了 struct 的第三方开发者有用。他们可能可以克隆库提供的现有对象之一。

关于c - 有一个没有定义的结构是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58263271/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com