2017-04-21 11 views
1

現在、私は割り当てを行っていますが、ノートパソコンではうまく動作しますが、PC上では出力がばかげています。2つのシステムで同じプログラムから出力されるC++の出力が異なります

のコマンドを入力します。

は、次のコマンドを入力します。
a'Zéÿコマンドを受け取りました。

なぜ私の混乱した出力を無視して、出力に「ゼー」があるのですか?
私のラップトップでは、コードは意図したとおりに動作します。ここ

は小さなサンプルコードである:そのわずか
`コマンドを受信して​​も

#include <sys/types.h> 
#include <sys/wait.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <iostream> 
using namespace std; 

int main(){ 
    int pipefd[2]; 
    pid_t cpid, ppid; 
    char buf[100]; 

    if (pipe(pipefd) == -1) { 
     perror("pipe"); 
     exit(EXIT_FAILURE); 
    } 

    cpid = fork(); 

    if (cpid == 0) { 
     read(pipefd[0], &buf, 1); 
     cout << buf << " command received." << endl; 
    } 
    else { 
     cout << "Enter a command: " << endl; 
     cin >> buf; 
     cout << "buf: " << buf << endl; 
     size_t len = strlen(buf); 
     write(pipefd[1], &buf, len); 
    } 

    return 0; 
} 

出力はslighty differntあります。
の代わりにコマンドを受信しました。

E:私は端末がurxvt

答えて

1
read(pipefd[0], &buf, 1); 

は1バイトを読み込みます。それは1バイトなので、それはプログラムだから印刷が未定義の動作です

cout << buf << " command received." << endl; 

で必要とされるヌルターミネータを読んでいるとは考えにくいです。 operator<<はどこで読書を止めるべきかわかりません。それはすぐに停止するかもしれません、それは有効なメモリの末尾に実行され、プログラムをクラッシュさせるかもしれません。確かな方法はなく、結果は毎回異なる可能性があります。

質問にプロトコル情報がないので、読んで何バイトを読まなければならないかを読者に知らせる通信プロトコルを確立することが私の唯一の提案です。メッセージを送信する前に、既知のサイズのカウンタを送信して、メッセージのサイズを読者に知らせるのが好きです。たとえば、その後、

uint32_t len = strlen(buf); 
write(pipefd[1], &len, sizeof(len)); 
write(pipefd[1], &buf, len); 

uint32_t len; 
read(pipefd[0], &len, sizeof(len)); 
read(pipefd[0], &buf, len); 

を読むためには、読み取りが成功したことを確認することを忘れて、あなたが必要とするバイト数を持っていないでください。メッセージ全体を受け取るまで、読み込みをループする必要があります。

+0

受信者が数字の桁数よりも少なく受信する可能性があるため、メッセージの長さに依存しないプロトコルです最初に送られた。より良い方法は、デリミタを使用することです。 jsonは '{message} 'を使った良い例です。 – alvits

+0

@alvits完全にプロトコルの必要性に依存します。デリミタのアプローチでは、区切り文字を見つけるためにgetta-byte getta-byte gettaバイト、バイト、バイトの読み込みパターンが必要ですが、これは適切ではない可能性があります。あなたは不注意に入力バッファをあふれさせることがあります。先頭に長さを付けると、受信者は事前に確認し、メッセージを処理するのに十分な記憶域があることを確認し、うまくいけば1つ大きな読み取りを行うことができます。 – user4581301

+0

私は同意しません。そのため、 'read()'の第3引数があります。これは、バッファオーバーランの保護手段です。送信者は、バッファが保持できる以上の長さの送信を許可されます。受信者はバッファが短ければループを介してすべてを読む責任があります。 – alvits

2

であるあなたは、バッファを初期化するために持っているか、そうでなければ、その場所にメモリに以前いたものは何でも含まれています両方のシステム上で、私のラップトップ上で私のPCや小学校にantergosを使用していますこれは印刷されているものです。

+0

しかし、なぜそれが私を混乱させる私のラップトップ上で正常に動作していることすべてが偶然に降りてくる – user273032

+0

:あなたのラップトップ上で、そこにはなりませんその場所にあるメモリに印刷可能な文字でなければなりません。 –

+0

@ user273032未定義の動作は未定義です。それは動作するように見えるかもしれません。 – user4581301

1

read()は、自動的にヌルバイトを付加しません。受信したメッセージの末尾にヌルバイトを付加するのはあなたの責任です。

最も簡単なのは、read()によって返された値を取得することです。この値は、読み取られたバイト数です。エラーが発生した場合は-1です。この戻り値を使用して、文字列の末尾をnullに設定します。

変更この行:

read(pipefd[0], buf, 1); 

へ:

また
int length=read(pipefd[0], buf, 99); 
if (length > 0) // length bytes was read 
    buf[length]='\0'; 
else // nothing was read or an error occured 
    buf[0]='\0'; 

あなたがNULLバイトを追加する必要はありませんので、あなただけのバッファ全体をゼロにすることができます。

変更この:これに

read(pipefd[0], buf, 1); 

memset(buf,0,100); 
read(pipefd[0], buf, 99); 
関連する問題