могу ли я рассчитывать на то, что мой компилятор оптимизирует strlen для const char *?

В моем обратном вызове синтаксического анализа SAX xml (XCode 4, LLVM) я делаю много вызовов для этого типа кода:

static const char* kFoo = "Bar";

void SaxCallBack(char* sax_string,.....)
{
     if ( strcmp(sax_string, kFoo, strlen(kFoo) ) == 0)
     {

     }


  }

Можно ли предположить, что strlen(kFoo) оптимизируется компилятором?

(В примере кода Apple был предварительно рассчитан strlen(kFoo), но я думаю, что это подвержено ошибкам при большом количестве постоянных строк.)

Редактировать: Мотивация для оптимизации: анализ моей карты SVG на iPod touch 2G занимает 5 секунд (!) с использованием NSXMLParser. Итак, я хочу переключиться на lib2xml и оптимизировать сравнение строк.


person Jacko    schedule 24.04.2011    source источник
comment
Совет по оптимизации новичкам: не делайте этого. Рекомендации по оптимизации экспертам: пока нет. Если профилирование не показало, что именно здесь находится узкое место в вашей программе, я думаю, вам не следует об этом беспокоиться.   -  person freespace    schedule 24.04.2011
comment
Вы имеете в виду strncmp, верно? Потому что вы могли бы просто использовать strcmp (с двумя аргументами), и это было бы эквивалентно условию в том виде, в каком оно написано сейчас.   -  person Pascal Cuoq    schedule 24.04.2011
comment
@freespace Вопрос в том, могу ли я рассчитывать на оптимизацию моего компилятора...?. Если вы не считаете, что этот совет относится к компиляторам, я не вижу, насколько он относится к этому вопросу.   -  person Pascal Cuoq    schedule 24.04.2011
comment
Почти никогда не бывает безопасно предполагать, что что-то будет оптимизировано компилятором, если только это не диктуется стандартом языка или вы не проверили, что это работает 10 раз раньше. Так что мой совет - просто проверить сгенерированную сборку :)   -  person Johan Kotlinski    schedule 24.04.2011
comment
Если это важно, вы можете проверить это. Но это не будет иметь значения, если этот код не будет вызываться миллионы раз в системе реального времени. И даже в этом случае, возможно, есть много мест, где ручная оптимизация помогает больше. Это не похоже на то, что эти строковые константы состоят из сотни слов.   -  person    schedule 24.04.2011
comment
@Pascal Cuoq, это имеет отношение к основной причине вопроса: Джеко считает, что это требует оптимизации, поэтому он спрашивает, сделает ли компилятор это за него. Я считаю, что важно понимать, когда исследовать оптимизацию компилятора, когда исследовать оптимизацию алгоритма, а когда не тратить время на оптимизацию.   -  person freespace    schedule 24.04.2011


Ответы (4)


Если под «LLVM» вы подразумеваете clang, то да, вы можете рассчитывать на clang -O для оптимизации strlen. Вот как выглядит код вашей функции:

_SaxCallBack:
Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    leaq    L_.str1(%rip), %rsi
    movl    $3, %edx
    callq   _strncmp
    ...

Я заменил strcmp на strncmp, но третий аргумент действительно был заменен непосредственным $3.

Обратите внимание, что gcc 4.2.1 -O3 не оптимизирует этот вызов strlen, и вы можете ожидать, что он будет работать только в точных условиях вашего вопроса (особенно строка и вызов strlen должны быть в одном и том же файле).

person Pascal Cuoq    schedule 24.04.2011
comment
Я проверил компилятор Microsoft. Он также оптимизировал вызов при использовании оптимизации /O2. - person Mark Wilkins; 24.04.2011
comment
gcc оптимизирует вызов strlen(), если сам kFoo становится const (т.е. static const char * const kFoo = "Bar";). - person caf; 24.04.2011
comment
clang version 2.8 не оптимизирует strlen() без второго const на моей машине. - person jfs; 24.04.2011
comment
GCC 4.5 и выше оптимизирует его в соответствии с быстрым тестом на gcc.godbolt.org: goo.gl/c9dgiq - person user31389; 20.01.2016

Не пишите такие вещи, как:

static const char* kFoo = "Bar";

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

Также не пишите такие вещи, как:

static const char *const kFoo = "Bar";

Теперь ваша переменная kFoo имеет const квалификацию и не поддается изменению, но если она используется в независимом от позиции коде (разделяемые библиотеки и т. д.), содержимое по-прежнему будет меняться во время выполнения и, таким образом, увеличит затраты памяти и запуска вашей программы. Вместо этого используйте:

static const char kFoo[] = "Bar";

или даже:

#define kFoo "Bar"
person R.. GitHub STOP HELPING ICE    schedule 24.04.2011
comment
Я бы не рекомендовал опцию #define в C++, определенно нет! Спасибо за внимание к проблеме с указателем. - person Matthieu M.; 26.04.2011
comment
Вопрос помечен как C, а не C++. Но да, я бы все равно предпочел форму static const char []. - person R.. GitHub STOP HELPING ICE; 26.04.2011
comment
Почему static const char kFoo[] не имеет проблемы с кодом, не зависящим от позиции? - person Joseph Garvin; 08.07.2011
comment
Проблема static const char * заключается в том, что вы создаете реальную переменную в сегменте данных, contents которого является адресом другого статического объекта продолжительности хранения (строковый литерал). Это значение варьируется в зависимости от адреса загрузки, поэтому оно должно быть исправлено (путем перемещения) во время загрузки. С static const char [] адрес не находится ни в одном объекте статической длительности хранения, и код, ссылающийся на массив, может получить к нему доступ через чистый, независимый от позиции адрес относительно ПК, который фиксируется во время компоновки. - person R.. GitHub STOP HELPING ICE; 08.07.2011
comment
@R.. Насколько я понимаю, объявление массива, с другой стороны, заставляет, по крайней мере, GCC фактически копировать весь литерал в стеке, фрагмент за фрагментом. В этом случае нужно взвесить, хотите ли вы заплатить штраф за исправление кода или выделение стека. Я прав? - person amn; 16.11.2013
comment
@amn: Вы были бы правы, если бы мы говорили об объектах с автоматической продолжительностью хранения, но они имеют статическую продолжительность хранения. - person R.. GitHub STOP HELPING ICE; 16.11.2013
comment
Точно, пропустил это. Тем не менее, как вы относитесь к тому, что статически выделенное хранилище, согласно C99, инициализируется с помощью 0s? Это тоже плата, не так ли? - person amn; 17.11.2013
comment
Статическое хранилище всегда инициализируется. Значение не имеет значения для стоимости любой разумной реализации. - person R.. GitHub STOP HELPING ICE; 17.11.2013

В общем, на это можно не рассчитывать. Однако вы можете использовать sizeof и применить его к строковому литералу. Конечно, это означает, что вы не можете определить «kFoo» так, как он был определен изначально.

Следующее должно работать на всех компиляторах и на всех уровнях оптимизации.

#define kFoo "..."

    ... strcmp(... sizeof(kFoo))
person Lindydancer    schedule 24.04.2011
comment
Обратите внимание, что в данном случае sizeof(kFoo) == strlen(kFoo) + 1 (sizeof включает завершающий NUL) - person vladr; 06.04.2012

Дополнительный вопрос:

Вы тестировали следующее?

static std::string const kFoo = "BAR";

void SaxCallBack(char* sax_string,.....)
{
  if ( sax_string == kFoo)
  {

  }


}

Это чистый выигрыш в удобочитаемости, но я понятия не имею о стоимости производительности.

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

person Matthieu M.    schedule 26.04.2011
comment
Спасибо, Матье. Я изучаю генератор конечного автомата под названием Ragel, который может генерировать синтаксические анализаторы на нескольких языках. - person Jacko; 28.04.2011