以整数为键并映射到 void 指针的 C 映射/哈希表

Posted

技术标签:

【中文标题】以整数为键并映射到 void 指针的 C 映射/哈希表【英文标题】:C map/hash-table that's keyed by integers and maps to void pointers 【发布时间】:2011-06-01 19:33:16 【问题描述】:

我正在将我在 Python 中使用 epoll 编写的轻量级图像服务器重写为 c(不是 c++)。我想编写一个(或使用现有的)非常简单的映射或哈希表,将整数键(文件描述符)映射到空指针。这样做的好方法是什么?我不需要能够支持任何通用类型的键甚至字符串。我有一个想法:

// Initialize map.
size_t map_size = 50;
void ** map = (void **)malloc(sizeof(void *) * map_size);
memset((void *)map, 0, map_size);

// Set values for keys 3, 20, 67
int key_a = 3;
int key_b = 20;
int key_c = 67;
void * value_a = ...;
void * value_b = ...;
void * value_c = ...;

// NOTE: This does not take into account conflicting keys. I would probably solve
// that using an array or linked-list and comparing keys.
map[key_a % map_size] = value_a;
map[key_b % map_size] = value_b;
map[key_c % map_size] = value_c;

这是明智的还是有更好的方法来实现这一点?或者有人可以指出我找到答案的正确方向吗?

【问题讨论】:

【参考方案1】:

其他人对这是否真的是您想要做的事情提出了很好的意见,但只是为了回答您的直接问题,glibc hashtable functions 应该在大多数系统上都可用。请注意,您几乎肯定希望使用 _r 变体 (hcreate_r, hsearch_r, hdestroy_r),因为原始版本创建和操作单个全局哈希表。

【讨论】:

我已经研究了 glibc 哈希表函数,但是您一次只能使用一个哈希表,我不想受到限制。 我认为这不对。正如我在上面的回复中提到的,使用 *_r 函数变体,它可以处理表并允许您一次创建多个表。 glibc 哈希表是按字符串而不是整数作为键的。【参考方案2】:

使用简单的模数作为“散列算法”本身并没有错,但只有在您知道结果会均匀分布的情况下才能正常工作。但是,在您的情况下,从技术上讲,您不能依靠文件描述符来指望它,因为没有特别保证您将从 open/fopen 调用中返回哪些数字。

那里有非常简单的哈希算法,它们非常快,并且对于一般用例来说工作得很好。您可以考虑FNV family,甚至是非常简单的 Pearson 哈希。

也就是说,我有点好奇您为什么要使用文件描述符作为键的哈希表。这似乎是一个奇怪的设计细节,让我觉得你把事情复杂化了。

【讨论】:

有一个关于您将从open() 调用中返回的号码的保证 - 它返回the lowest file descriptor not already open for the process。 我的原因是我希望能够将这些文件描述符映射到包含特定于每个文件描述符。文件描述符来自监听绑定到 IP 地址和端口并使用 epoll 注册的套接字。【参考方案3】:

在 Ruby 的代码库中使用通用 C 哈希表的公共域实现 -- st.c。

【讨论】:

【参考方案4】:

文件描述符在大多数系统上都是小整数,而且通常是连续的,因为它们在内核中用作索引。因此我建议只从 0..maxfd 创建一个数组(动态增长),并将文件描述符用作整数 - 根本没有散列。

作为安全防护,您可能希望防范使用不同策略分配文件描述符的系统,例如如果大于 2^20,则中止。

【讨论】:

文件描述符的 c 类型是 int,在大多数现代系统上是 32 位整数(即使在 64 位系统上,也不要与 long 混淆)。我在某处读到文件描述符的最大大小为 65535(一个无符号的 16 位整数),但我不知道这是否是常数。所以我只能传递数据类型的大小,这比我想要分配的数组大得多。特别是因为我认为数组的大小不需要比它将使用的最大同时连接数(文件描述符)大几个数量级。 文件描述符的类型是 int 并不意味着实现一定会耗尽 int 的整个值空间。在您关心的系统上(即那些实施 epoll - Linux),您可以依赖更多。

以上是关于以整数为键并映射到 void 指针的 C 映射/哈希表的主要内容,如果未能解决你的问题,请参考以下文章

在 JPA 中以实体为键映射 Map

使用c ++无序+映射的无效操作数

使用外键并映射到 EXTJS

Spring Data Elasticsearch 动态映射。将属性映射为键值?

在 Python 中使用 Excel 文件作为 pandas 数据框的映射

如何将通量元素转换为键映射单声道