C语言 C 和 H 文件中的 Typedef 和 Struct

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2483304/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:54:02  来源:igfitidea点击:

Typedef and Struct in C and H files

cstructincludetypedef

提问by Leif Andersen

I've been using the following code to create various struct, but only give people outside of the C file a pointer to it. (Yes, I know that they could potentially mess around with it, so it's not entirely like the private keyword in Java, but that's okay with me).

我一直在使用下面的代码来创建各种结构,但只给 C 文件之外的人一个指向它的指针。(是的,我知道他们可能会弄乱它,所以它并不完全像 Java 中的 private 关键字,但这对我来说没问题)。

Anyway, I've been using the following code, and I looked at it today, and I'm really surprised that it's actually working, can anyone explain why this is?

无论如何,我一直在使用以下代码,今天我看了它,我真的很惊讶它实际上可以工作,谁能解释一下这是为什么?

In my C file, I create my struct, but don't give it a tag in the typedef namespace:

在我的 C 文件中,我创建了我的结构,但不要在 typedef 命名空间中给它一个标签:

struct LABall {
    int x;
    int y;
    int radius;
    Vector velocity;
};

And in the H file, I put this:

在 H 文件中,我把这个:

typedef struct LABall* LABall;

I am obviously using #include "LABall.h" in the c file, but I am NOT using #include "LABall.c" in the header file, as that would defeat the whole purpose of a separate header file. So, why am I able to create a pointer to the LABall* struct in the H file when I haven't actually included it? Does it have something to do with the struct namespace working accross files, even when one file is in no way linked to another?

我显然在 c 文件中使用了 #include "LABall.h",但我没有在头文件中使用 #include "LABall.c",因为这会破坏单独头文件的全部目的。那么,当我实际上没有包含它时,为什么我能够在 H 文件中创建指向 LABall* 结构的指针?它是否与跨文件工作的 struct 命名空间有关,即使一个文件与另一个文件没有任何联系?

Thank you.

谢谢你。

采纳答案by rz0

Since you're asking a precise reason as to "why" the language works this way, I'm assuming you want some precise references. If you find that pedant, just skip the notes...

由于您要问“为什么”语言以这种方式工作的确切原因,我假设您需要一些精确的参考。如果你发现那个书呆子,就跳过笔记......

It works because of two things:

它之所以有效,是因为两件事:

  • All pointer to structure types have the same representation (note that it's nottrue of all pointer types, as far as standard C is concerned).[1] Hence, the compiler has enough information to generate proper code for all uses of your pointer-to-struct type.

  • The tag namespace (struct, enum, union) is indeed compatible accross all translation units.[2] Thus, the two structures (even though one is not completely defined, i.e. it lacks member declarations) are one and the same.

  • 所有指向结构类型的指针都具有相同的表示形式(注意,并非所有指针类型都如此,就标准 C 而言)。[1] 因此,编译器有足够的信息来为指向结构的指针类型的所有用途生成正确的代码。

  • 标签命名空间(struct、enum、union)确实兼容所有翻译单元。 [2] 因此,这两个结构(即使一个没有完全定义,即它没有成员声明)是一回事。

(BTW, #import is non-standard.)

(顺便说一句,#import 是非标准的。)

[1] As per n1256 §6.2.5.27:

[1] 根据 n1256 §6.2.5.27:

All pointers to structure types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.

所有指向结构类型的指针都应具有相同的表示和对齐要求。指向其他类型的指针不需要具有相同的表示或对齐要求。

[2] As per n1256 §6.2.7.1:

[2] 根据 n1256 §6.2.7.1:

two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, the other shall be declared with the same tag. If both are complete types, then the following additional requirements apply: [does not concern us].

如果它们的标签和成员满足以下要求,则在单独的翻译单元中声明的两个结构、联合或枚举类型是兼容的: 如果一个用标签声明,另一个应用相同的标签声明。如果两者都是完整类型,则适用以下附加要求:[与我们无关]。

回答by ndim

A standard pattern for stuff like that is to have a foo.hfile defining the API like

像这样的东西的标准模式是有一个foo.h定义 API的文件,如

typedef struct _Foo Foo;

Foo *foo_new();
void foo_do_something(Foo *foo);

and a foo.cfile providing an implementation for that API like

以及foo.c为该 API 提供实现的文件,例如

struct _Foo {
   int bar;
};

Foo *foo_new() {
    Foo *foo = malloc(sizeof(Foo));
    foo->bar = 0;
    return foo;
}

void foo_do_something(Foo *foo) {
    foo->bar++;
}

This hides all the memory layout and size of the struct in the implementation in foo.c, and the interface exposed via foo.his completely independent of those internals: A caller.cwhich only does #include "foo.h"will only have to store a pointer to something, and pointers are always the same size:

这将隐藏所有的内存布局,并在实施该结构的大小foo.c,并通过公开的接口foo.h是完全独立的内部组成:caller.c它不仅#include "foo.h"将只需要存储一个指针的东西,和指针总是相同的尺寸:

#include "foo.h"

void bleh() {
    Foo *f = foo_new();
    foo_do_something(f);
}

Note:I have left freeing the memory as an exercise to the reader. :-)

注意:我将释放内存作为练习留给读者。:-)

Of course, this means that the following file broken.cwill NOTwork:

当然,这意味着下面的文件broken.c工作:

#include "foo.h"

void broken() {
    Foo f;
    foo_do_something(&f);
}

as the memory size necessary for actually creating a variable of type Foois not known in this file.

因为实际创建类型变量所需的内存大小Foo在此文件中未知。

回答by kennytm

In

typedef struct A* B;

since all pointers' interfaces are the same, knowing that B means a pointer to a struct A contains enough information already. The actual implementation of A is irrelevant (this technique is called "opaque pointer".)

由于所有指针的接口都是相同的,知道 B 意味着指向结构 A 的指针已经包含足够的信息。A 的实际实现无关紧要(这种技术称为“不透明指针”。)

(BTW, better rename one of the LABall's. It's confusing that the same name is used for incompatible types.)

(顺便说一句,最好重命名LABall'之一。对于不兼容的类型使用相同的名称令人困惑。)