有时需要将字符串的长度与常量进行比较。
例如:
if ( line.length() > 2 )
{
// Do something...
}
但我试图避免在代码中使用“魔术”常量。
通常我使用这样的代码:
if ( line.length() > strlen("[]") )
{
// Do something...
}
由于函数调用,它更具可读性,但效率不高。
我写了模板函数如下:
template<size_t N>
size_t _lenof(const char (&)[N])
{
return N - 1;
}
template<size_t N>
size_t _lenof(const wchar_t (&)[N])
{
return N - 1;
}
// Using:
if ( line.length() > _lenof("[]") )
{
// Do something...
}
在发布版本(VisualStudio 2008)中,它生成了非常好的代码:
cmp dword ptr [esp+27Ch],2
jbe 011D7FA5
好的是编译器在二进制输出中不包含“[]”字符串。
它是特定于编译器的优化还是常见行为?
内联函数调用的能力是特定于编译器的优化 和 一种常见的行为。也就是说,许多编译器都可以这样做,但它们并不是必需的。
为什么不
sizeof“[]” - 1;
(减去一个尾随空值。你可以
sizeof“[]” - sizeof'\ 0',但sizeof'\ 0'
通常是C中的sizeof(int),而“ - 1”是
完全可读。)
我认为大多数编译器都会优化它 何时启用优化。如果他们被禁用,可能会使您的程序速度降低得多。
我更喜欢你的模板功能,因为他们保证不会打电话 strlen
在运行时。
当然,而不是为其编写单独的函数 char
和 wchar_t
,你可以添加另一个模板参数,并获得适用于任何类型的函数:
template <typename Char_t, int len>
int static_strlen(const Char_t (&)[N] array){
return len / sizeof(Char_t) - 1;
}
(正如在评论中已经提到的,如果传递了一组int,这会产生有趣的结果,但是你可能会这样做吗?毕竟这是为了字符串)
最后一点,这个名字 _strlen
是 坏。命名空间作用域中以下划线开头的所有名称都保留给实现。你冒着一些讨厌的命名冲突的风险。
顺便说一下,为什么“[]”比2更少的神奇常数?
在这两种情况下,如果与其进行比较的字符串格式发生变化,则必须更改文字。
#define TWO 2
#define STRING_LENGTH 2
/* ... etc ... */
说真的,为什么要经历所有这些麻烦只是为了避免键入2?老实说,我认为你的代码可读性较差,而其他程序员会盯着你,就像你从过滤器中抽出旧咖啡一样。