Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hash 编译时(预处理器)字符串哈希_Hash_C Preprocessor - Fatal编程技术网

Hash 编译时(预处理器)字符串哈希

Hash 编译时(预处理器)字符串哈希,hash,c-preprocessor,Hash,C Preprocessor,有没有办法在编译时使用C/C++预处理器(甚至是模板元编程)创建字符串哈希 e、 g.UNIQUE_SALT(“HelloWord”,3DES) 其思想是HelloWorld不会出现在编译的二进制文件中,只是一个散列 编辑:有许多这样的声明分布在一个大的代码库中。这可以通过Boost.MPL来完成,但它可能不是您想要的哈希类型 为什么不将生成哈希作为构建过程的一部分?您可以编写一个简单的批处理文件来生成散列(假设您有一个程序来执行此操作-如果没有,请编写一个),并让它输出一个预处理器指令,如:

有没有办法在编译时使用C/C++预处理器(甚至是模板元编程)创建字符串哈希

e、 g.
UNIQUE_SALT(“HelloWord”,3DES)

其思想是HelloWorld不会出现在编译的二进制文件中,只是一个散列


编辑:有许多这样的声明分布在一个大的代码库中。

这可以通过Boost.MPL来完成,但它可能不是您想要的哈希类型


为什么不将生成哈希作为构建过程的一部分?您可以编写一个简单的批处理文件来生成散列(假设您有一个程序来执行此操作-如果没有,请编写一个),并让它输出一个预处理器指令,如:

#define MY_HASH 123456789 

到一个.h文件,然后将其包含在应用程序中

对于C++0x,这是可能的,如和中的答案所述

在C++03中,没有编译时字符串处理。使用预处理器,您无法将字符串拆分为标记,使用模板,您无法访问单个字符。不过,有人就所推测的问题进行了讨论

对于C++03,您可以做的是按字符串方式传递(可能使用多字符文字):

foo=hash::result;
//或:
foo=hash::result;

。。。或者只是将其作为预构建步骤。

即使预处理器无法(合理地)完成此操作,如果使用字符串文字或将其声明为
static const
,并且没有创建对它的任何持久引用,编译器可能会继续进行所有运算以生成结果,如果使用优化编译,则会忽略目标文件中的字符串。最难的部分是,不能使代码初始化全局或静态变量太复杂,或者编译器会说“嘿,你!你不知道你不能在函数外使用for循环吗?”< /P> < P>我用一个好的OL C++标准偶然发现了一个解决方案。(我不确定考虑的是哪个版本,但假设此解决方案在Visual Studio中有效)

另外,这里有一个使用上述技术的JSHash函数的简短版本。这里显示的函数最多支持4个字符,不过您可以添加任意数量的字符

template<const char A = 0, const char B = 0, const char C = 0, const char D = 0>
struct cHash
{
    template<const char C, size_t hash = 1315423911>
    struct HashCalc
    {
        enum { value = (C == 0) ? hash : hash ^ ((hash << 5) + C + (hash >> 2)) };
    };

    enum { value = HashCalc<D,HashCalc<C,HashCalc<B,HashCalc<A>::value>::value>::value>::value };
};
模板
结构裂缝
{
模板
结构HashCalc
{
枚举{value=(C==0)?hash:hash^((hash>2))};
};
枚举{value=HashCalc::value};
};
如前所述,由于这是一个编译时哈希,您可以执行以下操作:

namespace Section
{
    enum Enum
    {
        Player = cHash<'p','l','a','y'>::value
    };
}
名称空间部分
{
枚举枚举
{
Player=cHash::value
};
}

这并不是最优雅的解决方案,所以我计划在这方面做更多的研究,但是因为这是我在VisualStudio2010中唯一能做的事情,所以就我当前的项目而言,我有点受限。

虽然这不是对这个问题的正确答案,但请参阅本博客文章,以获取字符串哈希函数的示例最多256个字符,仅作为C宏实现:

以下是博客中的实际代码:

#include <string.h>
#include <stdint.h>
#include <stdio.h>

#define H1(s,i,x)   (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x)   H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x)  H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x)  H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))

#define HASH(s)    ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#包括
#包括
#包括
#定义H1(s,i,x)(x*65599u+(uint8_t)s[(i)>16)))

如果您提前知道您将只对静态字符串使用它,那么可以用sizeof()替换strlen().

声称字符串不能在编译时解析的答案是错误的。字符指针不能在编译时解析,但字符串文字不是字符指针;它们是长度属于类型的字符数组。很容易忘记这一点,因为在大多数情况下,让它们衰减为char*.Bu更有用他们不是这样开始的

啊,但是如何真正定义一个采用固定长度字符数组的函数,特别是如果我们真的希望在任意长度的字符串上使用它的话?这就是模板参数推断非常方便的地方:

template<size_t L>
constexpr int hash(const char (&str)[L], int n = L - 1) {
    // hash goes here. You can define recursively as a
    // function of str[n] and hash(str, n-1). Remember to
    // treat 0 as a special case.
}
模板
constexpr int hash(const char(&str)[L],int n=L-1){
//散列在这里。您可以递归地定义为
//str[n]和hash(str,n-1)的函数。记住
//将0视为特例。
}

这应该让您开始了。显然,哈希本身需要足够简单,以进行编译时计算,但这可能没问题。

这就是我使用C++0x进行编译时字符串哈希的方法:

class StringHash
{
public:
    template <unsigned N, unsigned I>
    struct HashHelper
    {
        constexpr static unsigned Calculate(const char (&str)[N])
        {
            return (HashHelper<N, I - 1>::Calculate(str) ^ (str[I - 1] & 0xFF)) * StringHash::PRIME;
        }
    };

    template <unsigned N>
    struct HashHelper<N, 1>
    {
        constexpr static unsigned Calculate(const char (&str)[N])
        {
            return (StringHash::OFFSET ^ (str[0] & 0xFF)) * StringHash::PRIME;
        }
    };

    template<unsigned N>
    constexpr static unsigned StaticHash(const char (&str)[N])
    {
        return HashHelper<N, N>::Calculate(str);
    }

    static const unsigned OFFSET = 0x01234567;
    static const unsigned PRIME = 0x89ABCDEF;
}

我的问题不是生成散列,而是在编译时查找这些字符串并用它们的散列替换它们。我能想到的唯一方法是使用预处理器破解。有许多这样的独特的字符串(“某些字符串”,xxx)源代码管理中的声明。@Ashrus好吧,我仍然认为处理它们的最好方法是集中它们,然后以某种方式生成所需的定义。预构建步骤很简单!毕竟,它只是一些模式匹配/替换。任何脚本语言都允许您这样做,并且它将变得与使用PREP一样透明ocessor@Neil。它们不能集中。它们散布在源代码中(超过1M LOC,不在我的控制之下)这就是问题的空间。“我很欣赏这些替代方法,但实际上,你要求我重新定义问题空间,假设我在代码库和工具链上有一个水平的扭曲,我根本就没有,但是谢谢。谢谢,这和它的接近程度一样,但是我猜根据格奥尔的回答,当前C++是简单的。我猜其他类似的问题应该提醒我。如果我能接受两个答案,我也会接受你的答案。“hash::result”是如何工作的,为什么你不能执行“hash::result”?@ashrus:这些是多字符文字,有type
int
和“实现定义值”较长的值根本不适合于<代码> int <代码>,你仍然需要手动地分离出分离的字符值。抱歉,这是一个旧的帖子,但是是的,C++中是可能的。C++ + 0x使下面的方法更干净,但是我
class StringHash
{
public:
    template <unsigned N, unsigned I>
    struct HashHelper
    {
        constexpr static unsigned Calculate(const char (&str)[N])
        {
            return (HashHelper<N, I - 1>::Calculate(str) ^ (str[I - 1] & 0xFF)) * StringHash::PRIME;
        }
    };

    template <unsigned N>
    struct HashHelper<N, 1>
    {
        constexpr static unsigned Calculate(const char (&str)[N])
        {
            return (StringHash::OFFSET ^ (str[0] & 0xFF)) * StringHash::PRIME;
        }
    };

    template<unsigned N>
    constexpr static unsigned StaticHash(const char (&str)[N])
    {
        return HashHelper<N, N>::Calculate(str);
    }

    static const unsigned OFFSET = 0x01234567;
    static const unsigned PRIME = 0x89ABCDEF;
}
static hash = StringHash::StaticHash("Hello"); // You may even use this expression in `switch case`