18 ответов:
да
strlen()будет вычисляться на каждой итерации. Возможно, что в идеальных обстоятельствах оптимизатор может вывести, что значение не изменится, но я лично не буду полагаться на это.Я бы сделал что-то вроде
for (int i = 0, n = strlen(ss); i < n; ++i)или, возможно,
for (int i = 0; ss[i]; ++i)до тех пор, пока строка не будет изменять длину во время итерации. Если это возможно, то вам нужно будет либо позвонить
strlen()каждый раз, или обработать его более сложным логика.
да, каждый раз, когда вы используете петлю. Тогда он будет каждый раз вычислять длину строки. так что используйте его следующим образом:
char str[30]; for ( int i = 0; str[i] != ''; i++) { //Something; }В приведенном выше коде
str[i]проверяет только один конкретный символ в строке в местоположенииiкаждый раз, когда цикл начинает цикл, таким образом, это займет меньше памяти и является более эффективным.посмотреть этот ссылке для получения дополнительной информации.
в коде ниже каждый раз, когда цикл выполняется
strlenбудет считать длина всей строки, которая менее эффективна, занимает больше времени и занимает больше памяти.char str[]; for ( int i = 0; i < strlen(str); i++) { //Something; }
хороший компилятор не может вычислить его каждый раз, но я не думаю, что вы можете быть уверены, что каждый компилятор это делает.
кроме того, компилятор должен знать, что
strlen(ss)не меняется. Это верно только в том случае, еслиssне изменяется вforпетли.например, если вы используете только для чтения, функция
ssinforцикл, но не объявляйтеss- параметр asconstкомпилятор не может даже знать, чтоssне изменяется в цикл и должен вычислитьstrlen(ss)на каждой итерации.
если
ssтипаconst char *и вы не отбрасываетеconstness в цикле компилятор может вызывать толькоstrlenраз, если оптимизация включена. Но это, конечно, не то поведение, на которое можно рассчитывать.вы должны сохранить
strlenрезультат в переменной и использовать эту переменную в цикле. Если вы не хотите создавать дополнительную переменную, в зависимости от того, что вы делаете, вы можете быть ale, чтобы уйти с обратным циклом для итерации назад.for( auto i = strlen(s); i > 0; --i ) { // do whatever // remember value of s[strlen(s)] is the terminating NULL character }
формально да,
strlen()ожидается, что он будет вызываться для каждой итерации.в любом случае я не хочу отрицать возможность существования некоторой умной оптимизации компилятора, которая будет оптимизировать любой последовательный вызов strlen() после первого.
код предиката в полном объеме будет выполняться на каждой итерации
forпетли. Для того, чтобы запомнить результатstrlen(ss)вызов компилятора должен был бы знать, что по крайней мере
- функции
strlenбыл побочный эффект бесплатно- память, на которую указывает
ssне изменяется в течение всего циклакомпилятор не знает ни одной из этих вещей и, следовательно, не может безопасно запомнить результат первого звоните
Да
strlen(ss)рассчитаем длину на каждой итерации. Если вы увеличиваетеssкаким-то образом, а также увеличиваяi; там будет бесконечный цикл.
не распространено в настоящее время, но 20 лет назад на 16-битных платформах, я бы рекомендовал этот:
for ( char* p = str; *p; p++ ) { /* ... */ }даже если ваш компилятор не очень умен в оптимизации, приведенный выше код может привести к хорошему ассемблерному коду.
да. Тест не знает, что ss не изменяется внутри цикла. Если вы знаете, что это не изменится, то я бы написал:
int stringLength = strlen (ss); for ( int i = 0; i < stringLength; ++ i ) { // blabla }
да. strlen будет рассчитываться каждый раз, когда я увеличиваюсь.
Если вы не изменил ss С в курсе значит не повлияет на логику в противном случае это повлияет.
безопаснее использовать следующий код.
int length = strlen(ss); for ( int i = 0; i < length ; ++ i ) { // blabla }
Arrgh, это будет, даже при идеальных обстоятельствах, черт возьми!
на сегодняшний день (январь 2018), и gcc 7.3 и clang 5.0, если вы компилируете:
#include <string.h> void bar(char c); void foo(const char* __restrict__ ss) { for (int i = 0; i < strlen(ss); ++i) { bar(*ss); } }Итак, у нас есть:
ssпостоянный указатель.ssотмечается__restrict__- тело цикла никак не может коснуться памяти, на которую указывает
ss(ну, если это не нарушает__restrict__).и еще, оба компиляторы выполняют
strlen()каждая итерация этого цикла. Удивительный.это также означает, что аллюзии / принятие желаемого за действительное @Praetorian и @JaredPar не срабатывают.
да, простыми словами. И есть небольшое нет в редком состоянии, в котором компилятор хочет, как шаг оптимизации, если он обнаруживает, что нет никаких изменений, внесенных в
ssна всех. Но в безопасном состоянии вы должны думать, что это да. Есть некоторые ситуации, как вmultithreadedи управляемая событиями программа, она может получить багги, если вы считаете, что это нет. Играйте безопасно, так как это не слишком улучшит сложность программы.
да.
strlen()рассчитывается каждый раз, когдаiувеличивается и не оптимизирован.ниже кода показано, почему компилятор не должен оптимизировать
strlen().for ( int i = 0; i < strlen(ss); ++i ) { // Change ss string. ss[i] = 'a'; // Compiler should not optimize strlen(). }
мы можем легко проверить это :
char nums[] = "0123456789"; size_t end; int i; for( i=0, end=strlen(nums); i<strlen(nums); i++ ) { putchar( nums[i] ); num[--end] = 0; }условие цикла вычисляется после каждого повторения, перед перезапуском цикла .
Также будьте осторожны с типом, который вы используете для обработки длины строк . он должен быть!--1--> который был определен какunsigned intв stdio. сравнение и приведение его кintможет вызвать некоторые серьезные проблемы уязвимости.
ну, я заметил, что кто-то говорит, что он оптимизирован по умолчанию любой "умный" современный компилятор. Кстати посмотрите на результаты без оптимизации. Я попробовал:
минимальный код C:#include <stdio.h> #include <string.h> int main() { char *s="aaaa"; for (int i=0; i<strlen(s);i++) printf ("a"); return 0; }мой компилятор: g++ (Ubuntu / Linaro 4.6.3-1ubuntu5) 4.6.3
Команда для генерации ассемблерного кода: g++- S-masm=intel test.cppGotten assembly code at the output: ... L3: mov DWORD PTR [esp], 97 call putchar add DWORD PTR [esp+40], 1 .L2: THIS LOOP IS HERE **<b>mov ebx, DWORD PTR [esp+40] mov eax, DWORD PTR [esp+44] mov DWORD PTR [esp+28], -1 mov edx, eax mov eax, 0 mov ecx, DWORD PTR [esp+28] mov edi, edx repnz scasb</b>** AS YOU CAN SEE it's done every time mov eax, ecx not eax sub eax, 1 cmp ebx, eax setb al test al, al jne .L3 mov eax, 0 .....
развивая ответ Преториана, я рекомендую следующее:
for( auto i = strlen(s)-1; i > 0; --i ) {foo(s[i-1];}
autoпотому что вы не хотите заботиться о том, какой тип возвращает функция strlen. Компилятор C++11 (например,gcc -std=c++0x, не полностью C++11, но авто типы работают) сделает это за вас.i = strlen(s)потому что вы хотите сравнить в0(см. ниже)i > 0потому что сравнение с 0 (немного) быстрее, чем сравнение с любым другим число.недостатком является то, что вы должны использовать
i-1для доступа к строковым символам.
Comments