2009-09-08 2 views
10

Иногда приходится сравнивать длину строки с константой.
Например:Является ли время компиляции "strlen()" эффективным?

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 

И хорошо, что компилятор не включает Строка "[]" в двоичном выходе.

Является ли это конкретной оптимизацией для компилятора или это обычное поведение?

+2

Возможно, вы можете использовать один шаблон для всех типов массивов, что-то ложь: 'template size_t _lenof (const T (&) [N]) {return N - 1; } ', все равно будет работать так же, как ваш пример. –

+2

@Evan Teran: хорошая идея, но эти функции имеют смысл только для строк (массив char/wchar_t) из-за завершения «\ 0». Ваша функция будет работать для int [10] и вернуться 9 - я не думаю, что это имеет смысл;) – Dmitriy

+0

@ Dmitriy: действительно –

ответ

4

Возможность встроенного вызова функции - это как оптимизация для компилятора , так и. То есть многие компиляторы могут это сделать, но от них не требуется.

+0

Желаемая оптимизация не требует (просто) инкрустировать. Это требует, чтобы длина строки была вычислена во время компиляции. –

+0

Это не оптимизация. Длина не будет вычислена во время выполнения и все равно вызовет любую функцию '_lenof'. Разве стандартная * не требует * реализаций, чтобы дать строковым литералам тип 'const char [N]'? И не являются значения такого типа, необходимые для того, чтобы заставить компилятор выводить аргументы функции шаблона как 'N'? –

+0

Извините, я неправильно понял, о чем вы говорили - по какой-то причине я, хотя вы говорили о «неэффективном из-за вызова функции strlen». Если компилятор не может встроить _lenof, то он, вероятно, не может встроить что-либо, и будет довольно слабым компилятором C++ в целом. Любое серьезное использование шаблонов было бы кошмарным ... –

12

Почему не

 
sizeof "[]" - 1; 

(минус один за завершающим нулем Вы можете сделать SizeOf "[]". - SizeOf '\ 0', но SizeOf '\ 0' часто SizeOf (INT) в C, и «- 1» является отлично читается)

+0

не будет работать для широких строк (например, L "[]"). – Dmitriy

+1

может быть закреплен для широких струн. Что-то вроде: '(sizeof (L" [] ")/sizeof (L" ")) - 1' –

+0

@Evan Teran: да, но вы должны использовать макросы, чтобы сделать его более читаемым. IMHO-макросы больше C-стиля, но не C++ – Dmitriy

-7
#define TWO 2 
#define STRING_LENGTH 2 
/* ... etc ... */ 

Серьезно, почему пройти через все эти хлопоты, только чтобы избежать вводить 2.? Я искренне думаю, что вы делаете свой код менее удобочитаемым, и другие программисты будут смотреть на вас, как будто вы фырканье используемого кофе из фильтра.

+0

это просто пример. В реальном коде это выглядит как «некоторая строка». Собираетесь ли вы подсчитать количество символов в этом случае? :) – Dmitriy

+0

Да, я. И я буду. И я делаю. –

+2

@Jed Smith: :) Вы уверены, что не забудьте изменить определение макроса, если строка изменится? – Dmitriy

2

Я думаю, что большинство компиляторов будет оптимизировать его , если включена оптимизация. Если они отключены, это может замедлить работу вашей программы намного больше, чем необходимо.

Я бы предпочел, чтобы ваш шаблон функционировал, так как они гарантированно не позвонят strlen во время выполнения. Конечно, вместо того, чтобы писать отдельные функции для char и wchar_t, вы могли бы добавить еще один аргумент шаблона, а также получить функцию, которая работает для любого типа:

template <typename Char_t, int len> 
int static_strlen(const Char_t (&)[N] array){ 
    return len/sizeof(Char_t) - 1; 
} 

(Как уже упоминалось в комментариях, это даст смешные результаты если передается массив целых чисел, но вы, вероятно, чтобы сделать это? это означало для строк, в конце концов)

Заключительное примечание, имя _strlen является плохо. Все имена в области пространства имен, начинающиеся с символа подчеркивания, зарезервированы для реализации. Вы рискуете неприятными конфликтами именования.

Кстати, почему «[]« меньше магической константы, чем 2?

В обоих случаях это буква, который должен быть изменен, если формат строки, который он сравнивает с изменениями.

+0

По какой-то причине ваша функция не работает быстрее, чем при использовании strlen. Однако он работает быстрее, чем использование std :: char_traits :: length, поэтому оно по-прежнему полезно, поскольку strlen работает только с массивами char. – leetNightshade

Смежные вопросы