2009-09-08 10 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

おそらく、すべての配列型に対して1つのテンプレートを使用することができます。これは、次のようなものです: 'template size_t _lenof(const T(&)[N]){return N - 1; } 'は、あなたの例と同じように動作するはずです。 –

+2

@ Envan Teran:良いアイデアですが、これらの関数は '\ 0'を終了するため文字列(char/wchar_tの配列)に対してのみ意味があります。あなたの関数はint [10]で動作し、9を返します - それは意味をなさないと思います;) – Dmitriy

+0

@Dmitriy:確かに –

答えて

4

関数呼び出しをインライン化する機能は、コンパイラ固有の最適化の両方の共通の動作です。つまり、多くのコンパイラが実行できますが、必須ではありません。

+0

希望の最適化はインライン展開を必要としません。コンパイル時に文字列の長さを計算する必要があります。 –

+0

それは実際には最適化ではありません。長さは実行時には計算されず、 '_lenof'関数を呼び出します。標準の*実装では、文字列リテラルに 'const char [N]'型を与える必要はありませんか?そして、コンパイラがテンプレート関数の引数を 'N 'に推定するために必要な型の値ではないのですか? –

+0

申し訳ありませんが、私はあなたの答えが何を指しているのか誤解しました。何らかの理由で、「あなたは[strlen]関数呼び出しのために効率的ではありません。コンパイラが_lenofをインライン化できない場合は、インライン化できない可能性があり、一般的にはC++コンパイラとはかなり似ています。どんな深刻なテンプレートの使用も悪夢になるでしょう... –

12

なぜ

 
sizeof "[]" - 1; 

(マイナス末尾のヌルのための1つのあなたが はsizeof行うことができ、 "[]" - 。 '\ 0' はsizeofが、 '\ 0' は、多くの場合はsizeofでは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

これは単なる例です。実際のコードでは、 "some string"のように見えます。この場合、文字数を数えますか? :) – Dmitriy

+0

はい、ありがとうございます。そして私はそうするでしょう。そして私はそうします。 –

+2

@Jed Smith::)文字列が変更された場合にマクロ定義を変更することを忘れないでください。 – Dmitriy

2

最適化が有効になっている場合、ほとんどのコンパイラはを最適化すると思います。彼らが無効になっていると、必要以上にプログラムが遅くなる可能性があります。

実行時にstrlenを呼び出さないことが保証されているので、テンプレート関数が好きです。もちろん 、むしろcharwchar_tに別々の関数を書くよりも、あなたは別のテンプレート引数を追加し、任意のタイプのために働く機能を得ることができます:

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

すでにコメントで述べたように(、これは面白い結果が得られますintの配列が渡された場合、それを行う可能性がありますか?

最後に、_strlenの名前はです。です。アンダースコアで始まる名前空間スコープのすべての名前は、実装に予約されています。あなたはいくつかの厄介な命名の衝突を危険にさらします。

ところで、なぜ「[]」は2よりも魔法の定数が少ないのですか?

どちらの場合も、比較する文字列の形式が変更された場合、変更する必要のあるリテラルです。

+0

何らかの理由で、関数がstrlenを使用するよりも速く表示されません。しかし、それはstd :: char_traits :: lengthを使うよりも速く見えるので、strlenはchar配列でしか機能しないので、まだ便利です。 – leetNightshade

関連する問題