为什么C语言的设计者要这样做类型等价呢?
我正在学习 C,并且正在阅读有关类型等效的内容。
我很好奇,有人知道为什么他们对数组和指针使用结构等价,但对结构和联合使用声明等价吗?
为什么会有这样的差距? 与结构/联合进行声明等效以及对其他所有内容进行结构等效有什么好处?
I'm learning C and I'm reading about type equivalence.
I'm curious, does anyone have an opinion why they used structural equivalence for arrays and pointers but they used declaration equivalence for structs and unions?
Why the disparity there? What is the benefit of doing declaration equivalence with structs/unions and structural equivalence for everything else?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我确信其他人会提供 C 特定信息,但我会提到类型等效是编程语言理论中的经典主要问题之一。 确定两种类型实际上是否等效是一个比看起来更棘手的问题。
例如,这里有一些学术课程的概述幻灯片只是为了让你尝尝头痛的滋味。
I'm sure others will present C specific information, but I'll mention that type-equivalence is one of the classic main problems in programming languages theory. Determining whether two types are actually equivalent is a much trickier problem than it may seem.
For example, here are some overview slides from an academic course just to give you a taste of the headache.
我确信这是因为这在当时看起来是个好主意。
不要试图过度思考 C. Kernighan & 的设计。 Ritchie 正在设计一种可能对其他事情有好处的系统实现语言,但最终做出了他们后来后悔的决定(操作符优先级是最好的记录)。 标准委员会已经解决了一些问题,而另一些问题则根深蒂固。
正如 Uri 在他的回答中指出的那样,类型等效是一个难题,因此可能是 K&R 所关注的问题之一,因为他们希望尽快获得一个可以工作的编译器,而不是稍后获得一个干净的语言设计。
I'm sure it was because it looked like a good idea at the time.
Don't try to overthink the design of C. Kernighan & Ritchie were designing a system implementation language that might be good for other things, and wound up with decisions they regretted later (operator precedence being the best documented). Some of the issues were cleaned up by the Standards Committee, and others were too deeply ingrained.
As Uri points out in his answer, type equivalence is a difficult problem, and is therefore one of those likely to have been punted by K&R in a desire to get a working compiler soon rather than a clean language design later.
在很多方面,c 都是 20 世纪 70 年代汇编语言的清晰表达。 这些处理器上的数组是直接使用指针实现的,而 c 只是简单地复制该事实。
In a lot of ways c is a clean expression of assembly idiom from the 1970s. Arrays on these processors are implemented directly using pointers, and c simply copies that fact.
结构等效性很难检查。 指针和数组非常简单,但结构和联合类型更复杂。 在这些复杂类型上测试结构等效性非常困难,但对于指针和数组则更容易。
编辑
最初我写了一个处理值等价的答案而不是类型等价,所以它并不是真正的答案这个问题。 不过,我确实收到了一些赞成票,所以我决定留在这里。
我对[值等效]的了解是,指针和数组在内存中总是有一个非常简单的布局。 这使得进行简单的逐字节比较变得容易。
对于结构和联合,这种内存布局不一定这么简单。 例如,您可以拥有一个带有 int (32 位)和 double (64 位)的结构。 这样的结构需要 128 位内存,其中 32 位实际上与比较无关。 因此,逐字节比较是不可能的。 因此,声明等效性更容易实现。
Structural equivalence is difficult to check. Pointers and arrays are pretty simple, but structs and union types are more complex. Testing for structural equivalence is very difficult on these complex types, but easier for pointers and arrays.
EDIT
Originally I had written an answer that dealt with value equivalence instead of type equivalnce, so it wasn't really n answer to this question. I did receive a few upvotes on it, though, so I decided to keep in here.
What I know about [value equivalence], is that pointers and arrays always have a pretty simple layout in memory. This which makes it easy to do a simple byte-for-byte comparison.
For structs and union, this memory layout isn't necessarily this simple. You could for example, have a struct with an int (32 bit) and a double (64 bit). Such a struct requires 128 bits of memory, 32 of which aren't actually relevant for comparison. So, byte-forbyte comparison is out of the question. So, declaration equivalence is just easier to implement.
不要低估丹尼斯·里奇。 每种静态类型语言都应该有一种方法来创建用户无法伪造的抽象类型。 为此,您需要一个生成的类型构造或声明构造,即该构造的每个实例都会生成一个新类型,与任何其他类型不同。 如果您想让其他人远离您的数据,这样的结构至关重要。 (有关大量示例,请参阅 Dave Hanson 的书 C 接口和实现。
)这里的值
p1
和p2
具有不同的类型,但具有相同的表示形式:为什么选择
struct
来生成? 因为它足够通用,可以进行各种方便的表示。union
有点牵强,但我怀疑这是“附带设计”; 在 C 的类型系统中,union
表现出尽可能多的 liststruct
,这简化了编译器。顺便说一句,“声明等价”是我以前从未听说过的术语。 25 年前,“名称等效”、“结构等效”和“出现等效”等术语很流行。 今天的类型系统更加正式,并且等价性通常由逻辑规则而不是非正式英语定义。 当诉诸非正式英语有帮助时,我通常发现“生成性”的概念比为每种新语言的等价规则发明一个新名称更具解释力。
Don't underrate Dennis Ritchie. Every statically typed language should have a way to create an abstract type which it is impossible for a user to forge. For this you need a type construct or declaration construct that is generative, i.e., every instance of the construct generates a fresh type, distinct from any other. Such a construct is vital if you want to keep other people's mitts off your data. (For plenty of examples, see Dave Hanson's book C Interfaces and Implementations.)
So here values
p1
andp2
have different types but the same representation:Why pick
struct
to be generative? Because it's general enough to allow a wide range of convenient representations.union
is a bit of a stretch, but I suspect it's "collateral design"; in C's type system,union
behaves as much liststruct
as possible, which simplifies the compiler.Incidentally, "declaration equivalence" is a term I have never heard before. 25 years ago terms like "name equivalence", "structural equivalence", and "occurence equivalence" were popular. Today type systems are much more formal, and equivalence is typically defined by logical rules rather than informal English. When it is helpful to resort to informal English, I usually find that the idea of "generativity" has more explanatory power than inventing a new name for the equivalence rules of each new language.