次のコードが冗長な計算を引き起こす可能性があるのか 、それともコンパイラ固有のものなのかわかりませんか?
for (int i = 0; i < strlen(ss); ++i)
{
// blabla
}
増加strlen()
するたびに計算されますか?i
次のコードが冗長な計算を引き起こす可能性があるのか 、それともコンパイラ固有のものなのかわかりませんか?
for (int i = 0; i < strlen(ss); ++i)
{
// blabla
}
増加strlen()
するたびに計算されますか?i
はい、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] != '\0'; i++)
{
//Something;
}
上記のコードでは、ループがサイクルを開始するたびstr[i]
に location の文字列内の特定の 1 文字のみを検証するため、必要なメモリが少なくなり、より効率的になります。i
詳細については、このリンクを参照してください。
以下のコードでは、ループが実行されるたびにstrlen
文字列全体の長さをカウントしますが、これは効率が悪く、より多くの時間とメモリを必要とします。
char str[];
for ( int i = 0; i < strlen(str); i++)
{
//Something;
}
優れたコンパイラーは毎回計算するとは限りませんが、すべてのコンパイラーがそれを行うと確信できるとは思いません。
それに加えて、コンパイラはそれstrlen(ss)
が変わらないことを知る必要があります。これは、がループss
で変更されていない場合にのみ当てはまります。for
たとえば、読み取り専用関数をss
inループで使用するが、 -parameter を としてfor
宣言しない場合、コンパイラはそれがループで変更されていないことさえ認識できず、すべての反復で計算する必要があります。ss
const
ss
strlen(ss)
ss
が型const char *
であり、ループ内でネスをキャストしていない場合、最適化がオンになっている場合const
、コンパイラは 1 回だけ呼び出す可能性があります。strlen
しかし、これは確かに信頼できる行動ではありません。
結果を変数に保存し、strlen
この変数をループで使用する必要があります。追加の変数を作成したくない場合は、実行内容によっては、ループを逆にして逆方向に反復することで回避できる場合があります。
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
は、ループ中に変化しませんコンパイラはこれらのことのどちらも知らないため、最初の呼び出しの結果を安全に記憶することはできません
最近では一般的ではありませんが、20 年前の 16 ビット プラットフォームでは、次のことをお勧めします。
for ( char* p = str; *p; p++ ) { /* ... */ }
コンパイラの最適化があまり賢くなくても、上記のコードで適切なアセンブリ コードが得られる可能性があります。
はい。strlen は、i が増加するたびに計算されます。
ループ内でssを変更しなかった場合は、ロジックに影響しないことを意味し、そうでない場合は影響します。
次のコードを使用する方が安全です。
int length = strlen(ss);
for ( int i = 0; i < length ; ++ i )
{
// blabla
}
はい、 はstrlen(ss)
反復ごとに長さを計算します。ss
何らかの方法で を増やしていて、 ; も増やしている場合i
。無限ループになります。
はい、ループが評価されるたびstrlen()
に関数が呼び出されます。
効率を改善したい場合は、常にすべてをローカル変数に保存することを忘れないでください...時間はかかりますが、非常に便利です..
以下のようなコードを使用できます。
String str="ss";
int l = strlen(str);
for ( int i = 0; i < l ; i++ )
{
// blablabla
}
はい、strlen(ss)
コードが実行されるたびに計算されます。
はい。テストは、ループ内で ss が変更されないことを知りません。変わらないことがわかっている場合は、次のように書きます。
int stringLength = strlen (ss);
for ( int i = 0; i < stringLength; ++ i )
{
// blabla
}
まあ、誰かが「賢い」最新のコンパイラによってデフォルトで最適化されていると言っていることに気付きました。ところで、最適化なしの結果を見てください。私が試した:
最小限の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.cpp
Gotten 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
.....
はい。
strlen()
増加するたびに計算i
され、最適化されません。
以下のコードは、コンパイラが最適化すべきではない理由を示していますstrlen()
。
for ( int i = 0; i < strlen(ss); ++i )
{
// Change ss string.
ss[i] = 'a'; // Compiler should not optimize strlen().
}
はい、簡単に言えば。また、変更がまったく行われていないことがわかった場合の最適化ステップとして、コンパイラが望んでいるまれな状況では小さな no がありss
ます。しかし、安全な状態では、YES と考えるべきです。イベント駆動型プログラムのような状況がいくつかありmultithreaded
、NOと見なすとバグが発生する可能性があります。プログラムの複雑さがあまり改善されないため、安全にプレイしてください。
簡単にテストできます:
char nums[] = "0123456789";
size_t end;
int i;
for( i=0, end=strlen(nums); i<strlen(nums); i++ ) {
putchar( nums[i] );
num[--end] = 0;
}
ループ条件は、各繰り返しの後、ループを再開する前に評価されます。
また、string の長さを処理するために使用する型にも注意してください。stdio でsize_t
定義されているものでなければなりません。unsigned int
比較してキャストすると、int
重大な脆弱性の問題が発生する可能性があります。
プレトリアンの答えを詳しく説明すると、次のことをお勧めします。
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
、文字列文字にアクセスするために使用する必要があることです。