9

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 のループが適切に展開され、コンパイル時にその文字列のハッシュ値が計算されます。

ただし、文字列を 1 文字長くreturn DJBHash("012345678901234567");すると、それ以上折りたたまれず、条件付きジャンプ命令でループが生成されます。

任意の長さのリテラル文字列をコンパイル時の定数としてハッシュ値に折り畳みたいと思います。
これはできますか?

明確化

私の質問は、gcc でのコンスタント フォールディングの最適化に関するものでした (タイトルを参照してください - gccコンパイラタグを削除しないでください) 。これらのオプションについて知っておくとよいでしょう。すべての人の利益のために投稿してくれてありがとう。しかし、彼らは私の質問に直接答えません。

実際には、必要に応じて gcc のソース コードを変更してビルドできるように、gcc への移植に取り組んでいます。しかし、私はCに限定されており、この範囲でこの問題を解決したいと考えています.

4

4 に答える 4

7

OP は C での定数フォールディングに関心がありますが、その C++ 兄弟のためだけです。C++14 では、単純にconstexpr両方の関数の前に置き、ループを変更して、そうでstrlen()ないことを補うことができます。constexpr

#include<iostream>

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

   for(auto i = 0; i < 512; ++i) {
      if (*str == '\0') return hash;
      hash = ((hash << 5) + hash) + static_cast<unsigned int>(*str);   
   }

   return hash;
}

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

int main()
{
    constexpr auto h = f(); 
    std::cout << std::hex << h << "\n"; // 88a7b505
}

で Clang 3.4 SVN を使用したライブ例-std=c++1y

: 現在の Clang 実装は、while(*str != '\0'). 代わりに、戻り条件を内部に持つ 512 の有限ループが機能します。

于 2013-10-01T20:17:42.250 に答える