5

「C:\Program Files (x86)」で作業すると、そのパスの下のどこかにあるプログラムで奇妙な問題が発生しました。テストプログラムで動作を再現しました。

    int _tmain(int argc, _TCHAR* argv[])
{
    wprintf(L"%d\n", argc);
    for (int i = 0; i < argc; i++) {
        wprintf(L"%s\n", argv[i]);
    }
    return 0;
}

プログラムは、すべてのコマンド ライン引数 (プログラムを識別するために使用されるプログラムへのパスを含む) をカウントして返します。急いでいたので「HelloWorld.exe」と名付けました。

プログラムを実行する 3 つの方法で、2 つの異なる結果が得られますが、私は同じ結果を期待していました。

独自のディレクトリから HelloWorld.exe を実行すると、出力は次のようになります。

1
HelloWorld.exe

その出力は正しく、期待されています。

「P:\Test (x86)」にある HelloWorld.exe を別の場所から実行し、引用符で囲まれたパスを使用すると、出力は次のようになります。

1
P:\Test (x86)\HelloWorld.exe

その出力も正しく、期待されています。

ただし、HelloWorld.exe を別の場所から実行し、エスケープされたスペースと角かっこを含むパスを使用すると、プログラムは検出されます (つまり、パスは正しい) が、出力は間違っています。

2
P:\Test
(x86)\HelloWorld.exe

何らかの理由でエスケープされたスペース

P:\Test\^ ^(x86^)\HelloWorld.exe

何らかの理由でスペース読み取り演算子になり、プログラムを見つけるためにパスを1つの文字列として読み取った後、プログラムが参照する配列を作成する前に、実際には2つの文字列であると判断します.

この動作は、Windows XP (x86) と Windows Server 2008 R2 (x64) の両方で発生します。Windowsのすべての(NT)バージョンに存在すると思います。

4

1 に答える 1

5

アップデート:

おっとっと。おそらく、これは Windows のバグ (または用語の誤用) である可能性があります。

GetCommandLine()単純にそれを呼び出してコンソールに出力する簡単な小さなテスト プログラムを作成しました。

私はそれを呼び出しました:

テスト^ スペイン^ の^雨^は^主に^^平野^ ^(または^そう^彼ら^が言う^)に^降る^。

そして、これは出力です:

test スペインの雨は主に平野に降る (またはそう言う)。

したがって、ランタイム ライブラリはキャレットをまったく認識しないと思います。唯一のオプションは、ユーザーにエスケープの代わりに引用符を使用するように指示することです。


いいえ、Windows のバグではありません。これは、C ランタイム ライブラリのバグです (ただし、この場合は欠点または欠乏という用語を好むかもしれません)。

Windows はエスケープ文字を処理し、実行可能ファイルを探しています。しかし、それはコマンドラインを引数に分けるものではありません。Windows はmain関数を呼び出すものではありません (または_tmainこの場合)。PE ヘッダー内で定義されたエントリ ポイントでプロセスを開始するだけです。この場所には、いくつかの C ライブラリ コード (またはその動的呼び出し) があり、他のスタートアップ タスクの中で kernel32 関数を呼び出し、GetCommandLine()それをスペースで分割し、引用符を尊重しますが、明らかにキャレット エスケープは行いません。

それほど驚くべきことではありません。ほとんどの人は、Windows コマンド ラインでキャレットを使用して文字をエスケープできることを知っているとは思いません。私は確かにしませんでした。

これが実際の問題を引き起こしている場合、実際にキャレット エスケープを使用してプログラムを呼び出す人がいる場合は、その人に停止するように指示するか、独自のコマンド ライン解析ルーチンを作成して、の出力を渡しますGetCommandLine()。で渡されたものは無視してくださいmain

于 2012-08-24T14:23:23.660 に答える