为什么标准C库中没有Hashtable支持?这是有特定原因吗?
为什么标准C库中没有Hashtable支持?这是有特定原因吗?
在今天的标准下,C语言似乎有些不寻常,因为它没有定义任何有用的数据结构。没有。甚至没有字符串——如果你认为C字符串是一种数据结构,那么我们对“数据结构”的理解就存在分歧。
如果你喜欢C语言,那么可以把它看作是一个“空白的画布”……你的整个应用程序都是由你编写的代码和你选择引入的库组成的,再加上一些相当原始的标准库函数,可能会有一两个像qsort
这样的例外。如今人们使用C语言来实现诸如Python、Ruby、Apache或Linux内核之类的东西。这些项目都使用自己的数据结构,不太可能使用STL之类的东西。
许多C语言库实现了通用哈希表。有一些权衡,你可以选择自己喜欢的。其中一些可以使用回调进行配置。
既然有这么多能够实现你想要的功能的库,那么将哈希表添加到C标准中的意义是什么呢?
FILE *
:-) - paxdiabloFILE*
...这是一个很好的观点。 - Dietrich Epptypedef struct { char data [81]; } punchcard_t;
,并应在stdpunchcard.h中定义。它将成为“从函数返回通用人类可理解的字符串”的解决方案。 - DmytroUTHash
;如果你只是想快速实现某些功能,我会推荐它。它非常容易学习,并且可以在不创建大量对象的情况下工作。是的,作者完全滥用了宏来使其工作,但它足够小和简单,以至于我并不在意。 - sudo标准C库中没有哈希表,因为:
这就是ISO的工作方式。提出提案,然后接受或拒绝。
你必须小心添加到标准库中的内容,因为你有两个相互冲突的群体。作为一个用户,你可能希望将所有可能用到的数据结构都添加到标准库中,以使语言更加有用。
但是,作为一名语言实现者(顺便说一下,这些人很可能占据了各种工作组的大部分组成人员,因此他们的观点可能会产生更大的影响),你不希望费劲地去实现可能不会被所有人使用的东西。当C89出现时,所有已经存在的内容都是为了规范现有做法,而不是引入新的做法。从那时起,所有标准的迭代都可以做得更自由一些,但向后兼容仍然是一个重要问题。
其实,我也有矛盾。我希望在C中能够利用Java、C++或Python库的所有功能。当然,这会让新手学习所有内容变得更加困难,而且正如一位评论者所说,可能会使任何代码猴子都能够编写有用的代码,从而降低我的价值 :-)
我几乎已经拥有我需要的所有数据结构,它们来自于我漫长而(大多数情况下)辉煌的职业生涯。对于此类东西,你并不局限于标准库。你可以获得许多第三方工具来完成工作,或者(像我一样)你也可以自己动手。
如果你想知道在每个迭代中为什么做出某些决策,ISO(最初是ANSI,后来被ISO接管)通常会发布理由文档。ANSI的C89文档可以在这里找到。其中的一个美妙之处在于作用域:
本理由主要关注对基础文档中所描述的语言进行的添加、澄清和更改。它不是C语言作为整体的理由:委员会的任务是将现有语言编码,而不是设计新语言。本理由没有试图捍卫语言的现有语法,例如声明的语法或运算符的绑定。
我特别喜欢他们承认他们不负责在标准化之前可能存在的混乱局面。
但是,也许你问题的真正答案在于这一点,这是其中一个指导原则:
保持C语言的精神。 委员会的主要目标是保留C语言的传统精神。 C语言的精神有许多方面,但本质上是一个社区对C语言基础原则的情感共鸣。 C语言精神的某些方面可以用以下短语总结:
- 相信程序员。
- 不要阻止程序员做必须做的事情。
- 保持语言小巧简单。
- 只提供一种操作方式。
- 使其快速,即使不能保证可移植性。
第三个原则可能是标准化努力未大规模扩展库的主要原因,这也是委员会可能会被标记为C2038而不是C89的原因之一。
errno
、locale
和signal
,但我从未使用过其他任何头文件,不过话说回来,我并不是全球唯一的C语言程序员 :-) complex
、fenv
、inttypes
、iso646
和wctype
等内容是后来出现的,与C89的原则无关。您需要查看特定版本的原始文档。 - paxdiablo标准C库没有包含任何大型持久数据结构,包括列表、树、栈和哈希表。
如果没有询问原始C库的作者,很难给出确定的答案。然而,一个合理的解释是实现这种数据结构涉及各种权衡,只有应用程序的作者才能做出这些权衡。
请注意,POSIX标准C库确实指定了通用哈希表函数:hcreate()
、hsearch()
和hdestroy()
;还要注意它们的“一刀切”性质往往使它们不适用于大多数实际用例,从而支持上述论点。
hcreate_r
,该函数没有这个限制(但它是非POSIX扩展)。 - jjg由于缺乏模板
这只是一个猜测,但是像C++这样的语言没有模板使得实现容器非常不优雅,因为您需要数十个定义来涵盖所有可能的类型,更不用说用户定义的类型了。
有一些C的策略可以缓解这种情况,比如玩弄void *
,但它们会失去编译时的类型检查。
目前我推荐GLib和gnulib这两种实现:在C中实现字典的快速方法
#define TEMPLATE_TYPE int
,然后跟着#include "templated_binary_tree.h"
,每个需要支持的类型都要这样做。头文件在包含时使用任何存在的TEMPLATE_TYPE
来创建适合该类型的函数。虽然不太美观,但可以让它正常工作 :-) - paxdiablo