C++ 使用const char数组参数分析constexpr显示运行时执行
我在我的一个程序中做了很多哈希运算,所以我决定编写一个constexpr函数,它至少可以在编译时为我做一些哈希运算。在成功实现constexpr散列函数之后,我分析了代码,它实际上需要时间——这很奇怪,因为计算应该在编译时进行,而不是在运行时。使用G++4.7.3 下面是一些gprof输出,以及一个带有非constexpr实现的演示程序,因为constexpr函数很难读取,同时也显示了它的工作原理 我采纳了以下链接中的建议,制作了字符数组constexpr和const: 注意:为了简化演示,代码中删除了一些内容,例如测试和断言 1.)我的constexpr函数是否在运行时执行?(对我来说,这似乎很明显) 2)如果是,原因是什么?如何让它在编译时而不是运行时执行 gprof:C++ 使用const char数组参数分析constexpr显示运行时执行,c++,hash,constexpr,C++,Hash,Constexpr,我在我的一个程序中做了很多哈希运算,所以我决定编写一个constexpr函数,它至少可以在编译时为我做一些哈希运算。在成功实现constexpr散列函数之后,我分析了代码,它实际上需要时间——这很奇怪,因为计算应该在编译时进行,而不是在运行时。使用G++4.7.3 下面是一些gprof输出,以及一个带有非constexpr实现的演示程序,因为constexpr函数很难读取,同时也显示了它的工作原理 我采纳了以下链接中的建议,制作了字符数组constexpr和const: 注意:为了简化演示,代
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls us/call us/call name
50.00 0.06 0.06 600012 0.09 0.09 string_length(char const*, unsigned int)
36.36 0.10 0.04 50001 0.80 2.20 HASHOAT_CONSTEXPR(char const*, unsigned int, unsigned int, unsigned int)
9.09 0.10 0.01 1100022 0.01 0.01 oat_part_two(unsigned int const&)
4.55 0.11 0.01 50001 0.10 0.10 oat_part_six(unsigned int const&)
0.00 0.11 0.00 1650033 0.00 0.00 oat_part_one(unsigned int const&, char)
0.00 0.11 0.00 550011 0.00 0.00 oat_part_three(unsigned int const&)
0.00 0.11 0.00 200004 0.00 0.00 oat_part_four(unsigned int const&)
0.00 0.11 0.00 100002 0.00 0.00 oat_part_five(unsigned int const&)
0.00 0.11 0.00 1 0.00 0.00 HashOAT(char const*, unsigned int)
示范计划:
#include <cstdio>
#include <cstring>
// "One-at-a-time" Hash
// the non-constexpr implementation:
unsigned int HashOAT( const char *key, const unsigned int size = 1009 ); // size must be prime
unsigned int HashOAT( const char *key, const unsigned int size ) {
unsigned int h = 0;
const std::size_t len = strlen(key);
for ( std::size_t i = 0; i < len; ++i ) {
h += static_cast< unsigned int >( key[i] );
h += ( h << 10 );
h ^= ( h >> 6 );
}
h += ( h << 3 );
h ^= ( h >> 11 );
h += ( h << 15 );
return h % size;
}
constexpr unsigned int HASHOAT_CONSTEXPR( const char* str, const std::size_t size=1009, const std::size_t idx=0, const std::size_t h=0 );
constexpr unsigned int oat_part_one( const std::size_t& h, const char c );
constexpr unsigned int oat_part_two( const std::size_t& h );
constexpr unsigned int oat_part_three( const std::size_t& h );
constexpr unsigned int oat_part_four( const std::size_t& h );
constexpr unsigned int oat_part_five( const std::size_t& h );
constexpr unsigned int oat_part_six( const std::size_t& h );
constexpr unsigned int oat_part_one( const std::size_t& h, const char c ) {
return ( h + static_cast<unsigned int>( c ) );
}
constexpr unsigned int oat_part_two( const std::size_t& h ) {
return ( h << 10 );
}
constexpr unsigned int oat_part_three( const std::size_t& h ) {
return ( h >> 6 );
}
constexpr unsigned int oat_part_four( const std::size_t& h ) {
return ( h << 3 );
}
constexpr unsigned int oat_part_five( const std::size_t& h ) {
return ( h >> 11 );
}
constexpr unsigned int oat_part_six( const std::size_t& h ) {
return ( h << 15 );
}
constexpr std::size_t string_length( const char* str, std::size_t index = 0 ) {
return ( str == nullptr || str[index] == '\0' ) ? 0 : 1 + string_length( str, index+1 );
}
constexpr unsigned int HASHOAT_CONSTEXPR( const char* str, const std::size_t size, const std::size_t idx, const std::size_t h ) {
return (
( idx == string_length( str ) ) ? (
(
(
( h + oat_part_four( h ) ) ^
oat_part_five( h + oat_part_four( h ) )
) +
oat_part_six(
( h + oat_part_four( h ) ) ^
oat_part_five( h + oat_part_four( h ) )
)
) % size
) : (
HASHOAT_CONSTEXPR( str, size, idx+1,
(
oat_part_one( h, str[idx] ) +
oat_part_two( h + static_cast< unsigned int>( str[idx] ) )
) ^
oat_part_three( oat_part_one( h, str[idx] ) +
oat_part_two( oat_part_one( h, str[idx] ) )
)
)
)
);
}
int main ( void ) {
constexpr const char* str="Some String";
printf("Hash: %i\n", HashOAT(str) );
printf("Hash: %i\n", HASHOAT_CONSTEXPR(str) );
// make the program take some time so we can see if the constexpr function is actually taking run-time
for ( int i=0; i<50000; ++i ) {
HASHOAT_CONSTEXPR(str);
}
return 0;
}
#包括
#包括
//“一次一个”散列
//非constexpr实现:
无符号整数hashot(const char*键,const unsigned int size=1009);//大小必须是最基本的
无符号整数哈希(常量字符*键,常量无符号整数大小){
无符号整数h=0;
const std::size\u t len=strlen(键);
对于(标准::尺寸\u t i=0;i(键[i]);
h+=(h>6);
}
h+=(h>11);
h+=(h6);
}
constexpr无符号整数第四部分(const std::size\u t&h){
返回(h>11);
}
constexpr无符号整数第六部分(const std::size\u t&h){
返回(h(str[idx]))
) ^
第三部分(第一部分(h,str[idx])+
第二部分(第一部分(h,str[idx]))
)
)
)
);
}
内部主(空){
constexpr const char*str=“一些字符串”;
printf(“哈希:%i\n”,HashOAT(str));
printf(“哈希:%i\n”,HASHOAT_CONSTEXPR(str));
//让程序花费一些时间,这样我们就可以看到constexpr函数是否真的在运行时运行
因为(inti=0;i20天过去了,没有人回答,所以我决定再深入一点
在编译时(使用g++-O#)我想到了尝试各种优化级别
我对for循环进行了数百万次迭代(在一台相当旧的计算机上),并在优化级别0、1、2、3和4上对执行进行了计时
我还编译成ASM(使用G++-S)并检查了程序生成的程序集
我得出的结论是,constexpr函数,或者可能是特别复杂的constexpr函数,在低于2级的任何优化级别上都被视为普通函数。在2级或更高级别上,G++在编译时对函数进行了评估,但它们没有进入可执行文件(通过检查程序集。asm文件要短得多)。完全优化的可执行文件在不到一秒钟的时间内完成了执行,而未优化的可执行文件则花费了大约十倍的时间。此外,在使用gprof进行评测时,优化的可执行文件的输出中没有显示任何constexpr函数
底线是,当以优化级别2或更高级别编译时,constexpr仅在编译时得到评估。下面是关于slashdot上constexpr的最新讨论(阅读:参数),与VC2013相关,但仍然相关: