C语言 没有定义的外部结构的用法

km0tfn4u  于 2023-10-16  发布在  其他
关注(0)|答案(2)|浏览(103)

举例来说:
file2.c

struct myStruct {
  int a;
} A;

file1.c

extern struct myStruct A;

int main (void) {

}

使用gcc file1.c file2.c编译。

  • 如果我们不需要知道内部细节,这是在file1.c中使用全局变量A的有效方法吗(例如:函数调用--比如用FILE *
  • 当我们操作内部细节的时候,定义(例如与file1.c中的定义相同)是唯一必要的吗?
  • 如果这些定义不同(我注意到它使用同一个翻译单元中的定义--但这符合标准吗),有什么要说的吗?

前面的结构问题并没有涉及不包含定义的主题--只涉及如何正确地包含定义(在头文件中,在所有使用该结构的文件中都是一样的)

jucafojl

jucafojl1#

  • 如果我们不需要知道内部细节,这是在file1.c中使用全局变量A的有效方法吗(例如:函数调用--比如用FILE *

是的。但是在A的类型不完整的情况下,你不能用它做很多事情。获取它的地址是我能想到的最主要的一个。
请注意,使用指向A的指针与使用A本身是不同的。

  • 当我们操作内部细节的时候,定义(例如与file1.c中的定义相同)是唯一必要的吗?

不。如果你想的话,你还需要定义

  • 定义该类型的对象或具有该元素类型的数组;
  • 通过sizeof运算符计算类型或类型示例的大小;或
  • 定义一个结构或联合类型,该结构或联合类型具有相关类型的成员。

我可能漏掉了什么。

  • 如果这些定义不同(我注意到它使用同一个翻译单元中的定义--但这符合标准吗),有什么要说的吗?

如果同一对象的不同声明指定了不兼容的类型,则转换器和程序行为未定义。对于在不同翻译单元中声明的非限定结构类型,“兼容”意味着:

  • 如果其中一个类型是用标记声明的,那么两者都是用相同的标记声明的;
  • 这两种类型具有相同数量的成员、相同的名称、相同的顺序,并且对应的成员具有兼容的类型。

通常,这种兼容性要求是通过在头文件中声明所有想要使用它的文件的类型#include来满足的--这避免了引入该类型的不兼容版本的机会。

1szpjjfi

1szpjjfi2#

  • 如果我们不需要知道内部细节,这是在file1.c中使用全局变量A的有效方法吗(例如:函数调用--比如用FILE *

file1.c中没有使用对象A,因此file1.c不包含使用对象A的有效方法。
extern struct myStruct A;A的有效声明。这是对这个名字的有效使用。
通过这个声明,对象A可以在file1.c中通过获取其地址&A来引用,这对于将地址传递给其他文件中定义的例程很有用,其中struct myStruct的定义是可见的。
使用“opaque”类型(在file1.c中,我们可以看到有一个类型struct myStruct,但不能看到它的定义,所以它是“opaque”)的一种更常见的方法是让file2.c提供访问它们的例程,例如:

  • 一种例行程序struct myStruct *GetMyStruct(parameters);,为struct myStruct分配内存并返回指向它的指针。
  • 释放struct myStruct的例程。(可能只调用free,但可能更复杂,例如释放struct myStruct中的数据所指向的内容。
  • 以各种方式操作struct myStruct的脚本,例如在其中设置值,从中获取值,或在进一步的计算中使用它。

诸如上述的功能通常优于使用外部对象标识符。
另外,A不是全局变量。C没有任何全局命名空间。对于具有全局名称的语言,这意味着声明一次名称就可以使其在整个程序中可见。C没有这个。你可以用外部链接声明一个名称,它们可以链接在一起引用同一个对象或函数,但在每个使用该名称的翻译单元中需要有一个声明。这与全球不同。

  • 当我们操作内部细节的时候,定义(例如与file1.c中的定义相同)是唯一必要的吗?

在大多数情况下,是的,您需要类型的定义。
从技术上讲,您可以使用&A来获取A的地址,将其转换为unsigned char *,并使用生成的指针来操作A的字节。因此,可以在没有struct myStruct类型定义的情况下操作A,但这不是一件正常的事情。

  • 如果这些定义不同(我注意到它使用同一个翻译单元中的定义--但这符合标准吗),有什么要说的吗?

怎么不一样了

相关问题