2012-03-13 7 views
0

私は、マクロの定義とマクロの名前の2つの文字列にMakefileからマクロ定義を解析しています。たとえば、ここに私のMakefileからマクロ定義行です:Cプログラミングストリングの解析

マクロ-1 =ボディ-1

私のコードは、バスエラー/セグメンテーションフォールトを生成します。

static void parse_macro_def(const char* line) 
{ 
    char* m_name; 
    int name_pos = 0; 

    int i = 0; 
    while(line[i++] != '=')     //iterate until an equal sign is found 
    { 
     if(!isspace(line[i]))   //copy characters to m_name unless the character is whitespace 
     { 
     m_name[name_pos++] = line[i]; 
     } 
    } 
} 
m_name[name_pos] = '\0'; 

M_NAMEは、すべてのヘルプのマクロ-1 のおかげに設定する必要があります!

+2

行に '= '記号が含まれていないと、セグメント化エラーが発生することがあります。 – dreamlax

+2

また、 'm_name'のためにスペースを割り当てていないので、ポインタの値は不確定です。つまり、ポインターを指していないと思われる場所を指しています。 – dreamlax

+0

'strtok()'を使ってあなたの人生を楽にしましょう。 –

答えて

1

m_nameは初期化されていないので、ランダムに書き込んでクラッシュしています。

スペースを割り当てて返すか、(スペースの長さとともに)スペースを渡す必要がありますので、すべての場合に上書きしないようにしてください。


マクロ名の空白文字は、マクロ定義のバグであることに注意してください。空白を導くことができます。末尾に空白がある可能性があります。名前の途中に空白があってはいけません。今、あなたが有効であると仮定している場合は、解析するためにMakefileを働かせて、この微妙なことを無視して取り除くことができます。 makeの代替品を作成している場合は、できません。

文字列に等号があることを前もって確認していない場合は、文字列の最後から外れていないことを確認する必要があります(NUL '\0'をスキャンしないでください)。実際には、堅牢なコードでは、おそらくパラノイア外のことを確認するでしょう。

while (line[i] != '\0' && line[i] != '=') 
{ 
    ... 
} 

そして、私はあなたがwhile状態でiをインクリメントして、次の文字がループ本体内のスペースであるかどうかを確認することを実現し、ことを書きながら。それは少し慣習的なことです、私たちは言うでしょう。あなたがマクロに遭遇した場合:

MACRO=value 

ループ条件がOをチェックするとき、あなたはm_name=をコピーします。 AFAICSではMをコピーしません。

m_name[name_pos] = '\0'; 

任意の関数、したがって、構文エラーの外側にある:あなたのラインが


注意。

+0

私は 'm_name'が範囲外であると仮定していましたが、それはコンパイルしてsegfaultを得ることができると考えているので、タイプミスでした。 – dreamlax

+0

@dreamlax:私はそれが失敗している正確なコードを見ていないということを意味していると考えています。私たちは、明らかに明白なことを指摘することができますが、それはすべてについてです。 –

+0

ありがとう!!私の構文解析の仕事は、範囲外のm_nameはタイプミスでした。また、私は以前に文字列に等号があることを検証しました。 – CodeKingPlusPlus

0

m_nameは不確定ですが、あなたはそれに値を割り当てていません。おそらく、mallocまたはcallocへの呼び出しの戻り値を割り当てたいと思うでしょう。

また、行に=が含まれていない場合、ループは行末を過ぎて読み込まれます。 =または回線の最後(必要に応じて'\n'または)に到達すると、ループが終了するようにする必要があります。

0

コードにいくつかの欠陥があります。行の最初の文字を確認/コピーすることは決してありません(すぐにiを増やすため)。また、m_nameポイントはどこにもありません(未定義です)。

一般に、私は少し異なるアプローチを使用します。スペースを期待したい場所はわかりませんが、今は(あなたのコードがうまくいくと仮定して)あなたはすべてを連結しています。 "some value = something"(これは有効なコードではないことがわかっています)は、すべてのスペース文字をスキップするため、変数名 "somevalue"になります。

私はこのような何かを(それが後半だと私は眠いので、いくつかのバグが含まれるかもしれませんが、あなたが行うことを試みることができるかについていくつかのアイデアを与える必要があります)を使用したい:また

char name[256]; 
const char *start = line; // points to beginning of the line 
const char *end = strchr(line, '='); // returns a pointer to the position where there's an equal sign (if there's any; 0 otherwise) 
if (end) { // only try to parse if there's an equal sign 
    for(; start < end && isspace(*start); ++start); // this will effectively remove all leading space characters 
    for(; end > start && isspace(*(end - 1)); --end); // this will effectively remove all trailing space characters 
    strncpy(name, start, end - start); // copy the name 
    // do something else here 
} 

を他の部分で何をやろうとしているのかに応じて、何らかの正規表現ライブラリ(追加のオーバーヘッドがあなたのプロジェクトに依存する場合)を使用し、\s*(.*?)\s*=のような式を使用すると便利です。