如果您不介意溢出,那么只需将警告静音即可。无符号整数算术保证是模2的
n算术,其中
n是值表示中的位数,因此无论如何都是明确定义的。该警告是一种愚蠢的警告;它警告您正在使用无符号整数的主要特性。
我发现对于该函数的每个
使用,即使在函数中使用本地
#pragma warning( disable: 4307 )
,该警告仍然会出现。
重写代码可以消除32位哈希函数的警告:
constexpr auto hashFnv1a( char const* s, unsigned h = Fnv1aBasis )
-> unsigned
{
return !*s ? h : hashFnv1a(s + 1, static_cast<unsigned>( 1ULL*(h ^ *s) * Fnv1aPrime ));
}
即使通过广泛的谷歌搜索,也找不到任何方法来禁用有符号值的溢出警告,而保留无符号值的警告。因此,为了处理64位哈希函数,似乎唯一的途径是实现一个constexpr
64位无符号乘法函数。由于它是constexpr
,所以它的效率并不重要。因此:
#include <stdint.h>
namespace b32 {
static constexpr uint32_t Fnv1aBasis = 0x811C9DC5u;
static constexpr uint32_t Fnv1aPrime = 0x01000193u;
constexpr auto hashFnv1a( char const* s, uint32_t h = Fnv1aBasis )
-> uint32_t
{ return !*s ? h : hashFnv1a(s + 1, static_cast<uint32_t>( 1ULL*(h ^ *s)*Fnv1aPrime )); }
}
namespace b64 {
static constexpr uint64_t Fnv1aBasis = 0xCBF29CE484222325uLL;
static constexpr uint64_t Fnv1aPrime = 0x100000001B3uLL;
constexpr auto lo( uint64_t x )
-> uint64_t
{ return x & uint32_t( -1 ); }
constexpr auto hi( uint64_t x )
-> uint64_t
{ return x >> 32; }
constexpr auto mulu64( uint64_t a, uint64_t b )
-> uint64_t
{
return 0
+ (lo( a )*lo( b ) & uint32_t(-1))
+ (
(
(
(
(
hi( lo( a )*lo( b ) ) +
lo( a )*hi( b )
)
& uint32_t(-1)
)
+ hi( a )*lo( b )
)
& uint32_t(-1)
)
<< 32
);
}
constexpr auto hashFnv1a( char const* s, uint64_t h = Fnv1aBasis )
-> uint64_t
{ return !*s ? h : hashFnv1a( s + 1, mulu64( h ^ *s, Fnv1aPrime ) ); }
}
#include <assert.h>
#include <iostream>
using namespace std;
auto main()
-> int
{
constexpr auto x = b64::mulu64( b64::Fnv1aBasis, b64::Fnv1aPrime );
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning( disable: 4307 )
constexpr auto y = b64::Fnv1aBasis*b64::Fnv1aPrime;
# pragma warning( pop )
#else
constexpr auto y = b64::Fnv1aBasis*b64::Fnv1aPrime;
#endif
cout << x << endl;
cout << y << endl;
assert( x == y );
static constexpr const char* const s = "blah!";
constexpr unsigned xs = b32::hashFnv1a( s );
constexpr uint64_t ys = b64::hashFnv1a( s );
int a[1 + xs%2]; (void) a;
int b[1 + ys%2]; (void) b;
}
unsigned long long
吗? - Rakete1111/W2
和/W4
分别在 rextester 或 rise4fun 上编译时,并没有收到这个警告。 - uh oh somebody needs a pupperuint32_t
替代int
(unsigned int
可能是 16 位)。此外,char
可能 是signed
或unsigned
,如果是signed
,则可能是 1 的补码。 - Bathsheba(h ^ (static_cast<unsigned int>(*s))
。 - bolovchar
会被隐式转换为unsigned
。 - Cheers and hth. - Alf