短字符串的哈希函数

时间:2009-08-05 12:54:04

标签: c string math hash

我想将函数名从弱嵌入式系统发送到主机以进行调试。由于两者是通过带宽短的RS232连接的,我不想直接发送功能的名称。有大约15个字符长的函数名称,我有时想以相当高的速率发送这些名称。

我想到的解决方案是找到一个散列函数,它将这些函数名称散列为单个字节,并仅发送此字节。主机将扫描源中的所有函数,使用相同的函数计算它们的哈希值,然后将哈希值转换为原始字符串。

哈希函数必须是

  1. 短片串冲突。
  2. 简单(因为我的嵌入式系统中不需要太多代码)。
  3. 适合单个字节
  4. 显然,它不需要以任何方式保证安全,只有无碰撞。因此,我不认为使用与加密相关的哈希函数是值得的复杂性。

    示例代码:

    int myfunc() {
        sendToHost(hash("myfunc"));
    }
    

    然后主持人可以向我提供执行myfunc功能的时间列表。

    是否有一些已知的哈希函数可以保持上述条件?

    修改

    1. 我假设我将使用少于256个函数名。
    2. 我可以使用多个字节,两个字节可以让我很好。
    3. 我更喜欢使用哈希函数,而不是在客户端和服务器上使用相同的函数到字节映射,因为(1)我在客户端上没有映射实现,我不确定我是否想要把一个用于调试目的。 (2)它需要我的构建链中的另一个工具将function-name-table注入我的嵌入式系统代码中。哈希在这方面做得更好,即使这意味着我会在很多时候发生碰撞。

8 个答案:

答案 0 :(得分:8)

尝试minimal perfect hashing

  

最小完美哈希保证n个键将映射到0..n-1而不会发生任何冲突。

包含C代码。

答案 1 :(得分:3)

嗯只有256个可能的值,因为你将解析你的源代码以了解所有可能的函数,也许最好的方法是将一个数字归属于你的每个函数???

真正的哈希函数可能不会起作用,因为你只有256个哈希值。 但是您希望映射至少26 ^ 15个可能的值(假设仅限字母,不区分大小写的函数名称)。 即使你限制了可能的字符串数量(通过应用一些强制格式化),你也很难获得有意义的名字和有效的哈希函数。

答案 2 :(得分:3)

不,没有。

您只能使用8位哈希来制作无冲突的哈希码,甚至不接近它。如果允许长度超过一个字符的字符串,则可能的字符串多于可能的哈希码。

为什么不提取函数名称并给每个函数名称一个id?那么你只需要在电线的每一侧都有一个查找表。

(正如其他人已经表明,如果您已经拥有所有函数名称,则可以生成没有冲突的哈希算法,但是更容易为每个名称分配一个数字以生成查找表...)

答案 3 :(得分:3)

您可以使用Huffman tree根据程序中使用的频率缩写功能名称。最常见的函数可以缩写为1位,不太常见的函数可以缩写为4-5,非常罕见的函数可以缩写为10-15位等。霍夫曼树不是很难实现,但你必须对位对齐做一些事情。

Huffman tree

答案 4 :(得分:2)

如果您有办法跟踪代码中的函数(即在运行时生成的文本文件),您可以使用每个函数的内存位置。不完全是一个字节,但小于整个名称并保证是唯一的。这具有低开销的额外好处。你需要“解码”地址的只是将地址映射到实际名称的文本文件;这可以发送到远程位置,或者,正如我所提到的,存储在本地计算机上。

答案 5 :(得分:0)

在这种情况下,您可以使用enum来识别功能。在某个头文件中声明函数ID:

typedef enum
{
    FUNC_ID_main,
    FUNC_ID_myfunc,
    FUNC_ID_setled,
    FUNC_ID_soundbuzzer
} FUNC_ID_t;

然后在函数中:

int myfunc(void)
{
    sendFuncIDToHost(FUNC_ID_myfunc);
    ...
}

答案 6 :(得分:0)

如果发送方和接收方共享同一组函数名,则可以从这些函数名构建相同的哈希表。您可以使用获取哈希元素的路径来进行通信。这可以是{起始位置+跳数}来传达此信息。这将占用2个字节的带宽。对于固定大小的表(lineair探测),只需要最终索引来处理条目。

注意:构建两个“同步”哈希表时,插入顺序很重要; - )

答案 7 :(得分:0)

这里描述的是一种自己实现它的简单方法:http://www.devcodenote.com/2015/04/collision-free-string-hashing.html

以下是该帖子的摘录:

它的灵感来源于二进制数被解码并转换为十进制数格式的方式。每个二进制字符串表示唯一地映射到十进制格式的数字。

如果我们有一个大写英文字母的字符集,那么字符集的长度是26,其中A可以用数字0表示,B表示数字1,C表示数字2,依此类推,直到Z现在,每当我们想要将这个字符集的字符串映射到一个唯一的数字时,我们就会执行与二进制格式相同的转换