c - gcc 复杂常量折叠

标签 c gcc compiler-construction compiler-optimization constantfolding

gcc 似乎对复杂的常量折叠有一些限制。这是一个例子:

static inline unsigned int DJBHash(const char *str)
{
   int i;
   unsigned int hash = 5381;

   for(i = 0; i < strlen(str); i++)
   {
      hash = ((hash << 5) + hash) + str[i];   
   }

   return hash;
}

int f(void)
{   
    return DJBHash("01234567890123456");
}

当以 -O3 优化级别 (gcc 4.8) 运行时,它会很好地展开 DJBHash 中的循环并在编译期间计算该字符串的哈希值。

但是,当使字符串长一个字符时 return DJBHash("012345678901234567"); 它不再折叠它并生成一个带有条件跳转指令的循环。

我想将任意长度的文字字符串折叠到它的哈希值中作为编译时间常量。
这能做到吗?

澄清

我的问题是关于 gcc 的常量折叠优化(见标题 - 请不要删除 gcccompiler 标签)< br/> 这里的许多答案都试图用模板或 constexpr 来解决问题。很高兴了解这些选项,感谢您为了所有人的利益发布它们。但是,他们没有直接回答我的问题。

实际上,我正在开发 gcc 端口,因此如果需要,我可以更改和构建 gcc 源代码。但我仅限于 C,我想在这个范围内解决这个问题。

最佳答案

这是一个使用 constexpr 的版本。它在一个方面与其他方法略有不同——可以说,由于是递归的,因此最容易将字符串前后散列。例如,它为“abc”提供的值将是您通常期望从“cba”获得的值。我认为这不会对使用产生任何真正的影响,只要您始终如一地使用一个或另一个(但考虑到散列的变幻莫测,我对此可能是错误的)。

虽然它确实在编译时进行评估——例如,我们可以将结果用作 switch 语句中的标签:

#include <iostream>

unsigned constexpr const_hash(char const *input) {
    return *input ?
           static_cast<unsigned>(*input) + 33 * const_hash(input + 1) :
           5381;
}

int main(int argc, char **argv) {
    switch (const_hash(argv[1])) {
    case const_hash("one"): std::cout << "one"; break;
    case const_hash("two"): std::cout << "two"; break;
    }
}

显然,可能会发生冲突,因此您通常不想将它用作 case 语句标签——我这样做主要是为了强制出现一种情况,如果结果不是编译结果,它将无法编译-时间常数。

编辑:如果您关心哈希算法是否“正确”,我想这更准确(感谢@Abyx):

unsigned constexpr const_hash(char const *input, unsigned hash = 5381) {
    return *input ?
        const_hash(input + 1, hash * 33 + static_cast<unsigned>(*input)): 
        hash;
}

关于c - gcc 复杂常量折叠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19120326/

相关文章:

c - "bus error"带有(非常)简单的 opencv 程序(使用 Mac Os X)

c++ - cpp : "-c" is not a valid option to the preprocessor

c++ - cURL 特定的未定义引用

c - ws ://in a C program

c++ - 在 for 循环中反转?

更改 GtkButton 的标签

c - 使用更新的 CPU 指令支持构建向后兼容的二进制文件

performance - JIT 性能是否会因可写页面而受到影响?

c - 将内存映射到文件描述符(反向mmap)的系统调用?

c - 如何用C写一个程序来测量缓存的速度?