2010-12-03 7 views
6

ここでは簡単な背景があります:私は、クライアントとサーバープログラムがUNIXソケットを介してお互いに通信しています。受信したメッセージをサーバー側で解析するときに、strncmpを使用して実行するアクションを特定しようとしています。strncmpの適切な使用

私が抱えている問題は、strncmpの長さ引数に使用するものを正確に把握することです。これが問題になっている理由は、私のメッセージのいくつかが共通のプレフィックスを共有しているからです。たとえば、サーバーにプライマリ・サーバー・アドレスで応答するメッセージ「getPrimary」と、サーバーがプライマリ・サーバーのステータスで応答する「getPrimaryStatus」というメッセージがあります。私の最初の考えは次の操作を実行することでした。

if(strncmp(message,"getPrimary",strlen("getPrimary"))==0){ 
    return foo; 
} 
else if(strncmp(message,"getPrimaryStatus",strlen("getPrimaryStatus"))==0){ 
    return bar; 
} 

これに伴う問題は、私はサーバー「getPrimaryStatus」を送信するときにstrncmpは、文字列に十分チェックされていないため、コードは常にFOOを返しますです。私はstrncmpの長さ引数としてstrlen(message)を渡すことができましたが、予期しない入力の場合にオーバーフローを防ぐstrncmpの使用目的を無効にするようです。私は読むことができる最大メッセージ長のための静的変数を持っていますが、長さがメッセージのオーバーフローがエフェクトが最小化されていることを確認しているので、これを渡すように思えます。

私はいくつかの解決策を考え出しましたが、それほどきれいではないので、この問題に対処する共通の方法があるかどうかは疑問でした。

参考までに私の現在の解決策は次のとおりです:共通の接頭辞を持つメッセージが長さの降順でチェックされるように、if/else if文を注文します(これは地雷を投げる本当に良い方法のようです後で何かを追加しようとしている人のために私のコードに書いておいてください)。

グループでは、私の共通の接頭辞を持つメッセージを一緒に最初の接尾辞を探します。

if(strncmp(message,"getPrimary",strlen("getPrimary"))==0){ 
    if(strncmp(message,"getPrimaryStatus",strlen("getPrimaryStatus"))==0){ 
     return bar; 
    else 
     return foo; 
    } 
} 

をしかし、これはちょうど私が私が扱うよ約20の異なる可能なメッセージを持っている、特に以来、汚い感じています。

私が持っているすべてのメッセージの配列を作成し、長さを降順に並べ替える関数をinitシーケンスに追加し、マッチするものが見つかるまでそのリストの要素を検索します。これは複雑で愚かなようです。

これは、どこかに解決策があるはずの共通の問題であるはずですが、これまで何も見つけられていないようです。

ありがとうございました!

答えて

4

、ここstrncmp()ではなくstrcmp()を使用する唯一の理由は、messageがある場合には、それはmessageの端部を越えて探して防ぐためにするだろうではありません。はNULLで終了します。このよう

、あなたがstrncmp()に渡すnは、あなたが(メッセージを読み取るread()/recv()関数の戻り値から)知っているべき、messageの受信された大きさであるべきです。

/* len is a placeholder for whatever variable or function you use to get the length */ 
if ((len(a) == len(b)) && (strncmp(a, b, len(a)) == 0)) 
{ 
    /* Strings are equal */ 
} 

は、そうでなければ、あなたの比較よりも長いか短いものにマッチします:

+0

これは最も簡単な解決策です。これは実際にはプロセス間通信を容易にするためにUnixソケットを使用して初めてのことですが、私は2ヶ月前にソケット処理コードを書いていました...私は読み込みバイト数を返すread()を使っていたことを完全に忘れてしまいました! –

+0

代わりに、メッセージサイズをstrncmpに渡すことは、あなたの問題に対する不完全な解決策だと思います。詳細は私のソリューションをご覧ください。 –

+0

多くの一致する文字を含む文字列間の比較は、「チャンク」手法を使用して最も効率的に実行できますが、早い時期に異なる文字列間の比較は文字単位のアプローチを使用する方が効率的です。 "n"が大きいときにstrncmpの実装がチャンクを使用すると、驚くことはありませんが、可能性のあるユースケースとそうでない場所の別々の機能があると良いでしょう。 – supercat

0

私の記憶から一年前のCプログラミングを掘り起こすと、3番目の議論は関数にいくつの文字を比較するかを伝えると考えられます。 strncmp()を使用しないでください

if(strncmp(message, "getPrimary", strlen("getPrimary")) { 
    // 
} 
0

:あなたがそうであるべきようなものを

を処理する方法に多くの文字を管理しているとして、それは安全である理由です。代わりに strlcmp()を使用してください。それはより安全です。

+2

strlcmp()は標準の一部ではないようです。私がオンラインで見つけた実装が典型的なものであれば、その文字列が他の文字列のサブセットであれば、その動作はstrncmp()の動作に縮退します。それはOPが望んでいないものです。 –

1

バッファオーバーフローを防ぐためにstrncmpを使用していますが、メッセージはすでにメモリ(つまりメッセージバッファ)にコピーされています。また、プロトタイプ

int strncmp (const char * str1, const char * str2, size_t num); 

関数が副作用を持たない(すなわち、それはいずれかの入力バッファを変更しない)ので、バッファを上書きし、メモリを変更すること危険があってはならないことを示しています。 (これはstrcpy()では当てはまりません)。

メッセージバッファの長さが最長のコマンド文字列より長いことを確認できます。そうすれば、自分が所有しているメモリに常にアクセスしていると確信できます。

また、strncmpの使用を強くお勧めする場合は、コマンドリストを配列に格納し、最大から最小の順に並べ替えることができます。各文字列を長さに関連付けることができます(場合によってはハンドラを実行するための関数ポインタ)。

最後に、C++がマップと呼ぶものや、RubyやPHPが連想配列を呼び出すものを見つけることができます。これにより、ライブラリがこのif-elseツリーを効率的かつ正確に処理できるようになります。

0

あなたのメッセージには、これらのコマンドの1つだけ、またはコマンド文字列の後に空白/括弧/括弧などが含まれていますか?

前者の場合は、strncmpをドロップし、strcmpを使用してください。

後者の場合は、単にisspace(message[strlen(command)])またはmessage[strlen(command)]=='('またはそれに類するものをチェックします。 (注:strlen(command)は定数であり、おそらくそれを書くか、文字列リテラルのサイズから取得するためにマクロを使うべきです)。

+1

'sizeof(" KeyWord ") - 1' - ' sizeof() 'も端末ヌルをカウントするためです。もちろんコンパイル時定数です。 –

+0

はい、私はそれをすべて言及すべきだったと思います。 –

2

1つの手法は、最長の名前を最初に比較することですまたはキーワードを含むテーブル)を使用して、より長い名前が短いものに先行するようにします。しかし、あなたの例を取る:

GetPrimaryStatus 
GetPrimary 

おそらくGetPrimaryIgnitionGetPrimaryとして認識されていないことを確認します。したがって、実際には、メッセージまたはキーワードの2つの文字列のうち長い方の長さを使用して比較する必要があります。ここ

あなたのデータ構造は次のようになります。

static const struct 
{ 
    char *name; 
    size_t name_len; 
    int  retval; 
} Messages[] = 
{ 
    { "getPrimaryStatus", sizeof("getPrimaryStatus"), CMD_PRIMARYSTATUS }, 
    { "getPrimary",  sizeof("getPrimary"),  CMD_PRIMARY  }, 
    ... 
}; 

あなたは、このテーブルをループには、関連するコマンドを見つけることができます。あなたが見なければならない範囲を制限することができます。 sizeof()の値には、文字列の末尾にNULが含まれています。これは、メッセージをNULLで終えることができる場合に便利です。

ただし、メッセージをどこかにコピーするか、またはその場でメッセージを変更することで、メッセージ内のコマンドワードをnullで終えることができます。 strncmp()の代わりにstrcmp()を使用します。最短一意のプレフィックス検索はコード化するのが難しい。

コマンドワードを検索するには、strcspn()を使用します。コマンドはすべて英字または英数字であると仮定します。 message内の文字列がnullで終了するをを想定していることを仮定

0

2つの文字列が等しいかどうかを判断するためにstrncmpはを使用するための唯一の安全な方法は、文字列が同じ長さを持っていることを事前に確認することです。

strncmp(a, "test", strlen("test"))は、 "テスト"、 "テストと他の文字の一束"などと一致します。

strncmp(a, "test", strlen(a))は、 ""、 "t"、 "te"、 "tes"と一致します。

0

strcmpを使用しますが、2つの文字列の長さも比較してください。長さが同じなら、strcmpはあなたが求める結果を与えます。