0

C サブプロセスに大量のデータを非常に高速に書き込むと、Broken Pipe エラーが発生します。

だから私はpythonスクリプトからacサブプロセスを実行しています:

process = subprocess.Popen("./gpiopwm", stdin=subprocess.PIPE)
while True:
    process.stdin.write("m2000\n")
    print "bytes written"

gpiopwm.c のメイン ループのセクション:

printf("1\n");
while (1) {
    fgets(input,7,stdin);  // Takes input from python script
    printf("2\n");

    numbers = input+1;      // stores all but first char of input 
    char first = input[0];  // stores first char of input

    if (first=='m') {
        printf("3\n");
        printf("%s\n",numbers);
    }
}

ただし、これからの出力は次のとおりです。

1
bytes written
Traceback (most recent call last):
     File "serial-receive-to-pwm.py", line 20, in <module>
     process.stdin.write("m2000\n")
IOError: [Errno 32] Broken pipe

C プログラムは明らかにそのfgets行で壊れており、出力される2ことはありません。私は何を間違えましたか?どうすればこれを回避できますか?

編集:fgets逆参照引数が含まれないように行を更新しましたが、パイプの破損エラーがまだ発生しています。

EDIT: inputとして初期化されますchar *input="m2000";

4

1 に答える 1

2

コンソールから C プログラムを実行しようとすると、クラッシュすることがわかります。デバッガーで実行すると、次の行にあることがわかります。

fgets(*input,7,stdin);

input文字配列のように見えますが、逆参照すると*input、ポインターではなく単一のchar値が渡されます。これにより、未定義の動作とクラッシュが発生します。

その行は、エラーではないにしても、コンパイラからの非常に大きな警告メッセージを表示するはずです。警告メッセージを無視しないでください。警告メッセージは、多くの場合、何か間違ったことをしている兆候であり、危険な可能性があることを示しています。


一般的なヒント: ここで行っているように、別のプログラムから呼び出す必要があるプログラムを開発する場合は、最初にプログラムをテストして動作することを確認してください。うまくいかない場合は、まず修正してください。

最後のヒント:宛先文字列に改行が含まれていることを忘れないでください。それを確認して、そこにある場合は削除することをお勧めします。fgets


最後の編集では、本当のinput問題を知っているという宣言を示しています。定数データを変更しようとしていて、データの境界を超えて書き込もうとしています。

リテラル文字列を指すときはinput、すべてのリテラル文字列が読み取り専用であることを覚えておく必要があります。リテラル文字列は変更できません。そうしようとすることは未定義の動作です。さらに悪いことに、文字列の長さはわずか 6 文字ですが、それに 7 文字を書き込もうとします。

最初に の宣言と初期化を変更しますinput

char input[16] = "m2000\n";

これにより、スタック上に配置され、変更可能な配列として宣言されます。それからする

while (fgets(input, sizeof(input), stdin) != NULL) { ... }

これにより、次の 2 つのことが達成されます。まず、サイズとして使用することで、 が範囲外に書き込まれないことをsizeof(input)確認できます。fgets第二に、ループ条件で呼び出しを使用することによりfgets、Python スクリプトが中断されたときにループが終了し、何も読み取れずに永遠にループして、読み取ったことのないデータで作業することはありません。

于 2013-12-20T11:42:15.613 に答える