GCC复杂的常量折叠 [英] gcc complex constant folding

查看:268
本文介绍了GCC复杂的常量折叠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看来GCC有复杂的常量折叠一定的局限性。下面是一个例子:

It seems that gcc has some limitation on complex constant folding. Here is an example:

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循环很好,在编译时计算该字符串的哈希值。

When running with -O3 optimization level (gcc 4.8), it unfolds the loop in DJBHash nicely and calculates the hash value for that string during compile time.

然而,使得串一个字符长时返回DJBHash(012345678901234567); 它并没有任何更多折叠,并生成一个条件跳转指令的循环。

However, when making the string one character longer return DJBHash("012345678901234567"); it does not fold it any more and generates a loop with a conditional jump instruction.

我想任意长度的文本字符串折叠成其散列值作为一个编译时间常数。结果
可以这样做吗?

I would like to fold a literal string in any length into its hash value as a compile time constant.
Could this be done?

我的问题是关于GCC恒折叠优化(见标题 - 请不要删除的gcc 的和的编译的标签)< BR>
很多答案在这里试图用任何模板或constexpr来解决问题。这是很好的了解这些选项,并感谢张贴的所有人的利益。然而,他们不直接回答我的问题。

My question was about the constant-folding optimizations on gcc (see the title - please do not remove gcc and compiler tags)
Many answers here try to solve the problem with either Templates or constexpr. It's good to know about these options and thanks for posting them for the benefit of all. However, they do not directly answer my question.

实际上,我的工作gcc的一个端口上,所以如果需要我可以改变和构建GCC源$ C ​​$ C。但我有限的为C,我想在此范围内解决这个问题。

Practically, I'm working on a gcc port so I could change and build gcc source code, if needed. But I'm limited to C and I would like to solve this problem in this scope.

推荐答案

下面是一个使用版本 constexpr 。这是一个从别人在某一方面略有不同 - 是递归的,这是最简单的散列字符串后到前,可以这么说。例如,它的价值给出了ABC会是什么你通常​​从CBA,而不是期望。我不认为这应该在使用任何真正的区别,只要你使用一个或其他一致(散列但考虑到变幻莫测,我可能是错了)。

Here's a version using constexpr. It's slightly different from the others in one respect -- being recursive, it was easiest to hash the string back to front, so to speak. For example, the value it gives for "abc" will be what you'd normally expect from "cba" instead. I don't think this should make any real difference in use, as long as you use one or the other consistently (but given the vagaries of hashing, I could be wrong about that).

它在编译时评估虽然 - 例如,我们可以使用结果在开关标签语句:

It does evaluate at compile time though -- for example, we can use the results as labels in a switch statement:

#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语句的标签 - 我主要是这样做是为了迫使它会失败的情况下进行编译,如果结果不是之前编制时间常数。

Obviously, there could be collisions, so you generally wouldn't want to use it as case statement labels -- I mostly did that to force a situation in which it would fail to compile if the result wasn't a compile-time constant.

编辑:如果你关心的哈希算法是正确的,我想这是更准确的(与感谢@Abyx):

if you care about the hash algorithm being "correct", I guess this is more accurate (with thanks to @Abyx):

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

这篇关于GCC复杂的常量折叠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆