C言語初心者です。
既存のプログラムを直そうとしているのですが、ポインタの概念がいまいち理解できていないのか、修正した箇所がうまく動きません。
どうすればよいかをご教示いただけませんでしょうか。
元のプログラムは
void sub()
{
SOCKET s;
struct msg r_msg;
int time;
int cc;
cc = sub_recv(s, &r_msg, time);
・・・
}
void sub_recv(s,*msg,time)
{
unsigned char *pack;
int cc;
int len;
pack = (unsigend char *)msg
cc = recv(s, (char *)pack, len, 0);
if(cc < 0)
return(cc);
・・・
}
という感じでr_msg構造体にrecvで受け取ったものを入れて行きます。
ccにはrecv()の戻り値でサイズが返ってきて直後のifにはひっかかりません。
構造体の中でサイズが固定されているため、可変にするために以下のようにしたいです。
extern int buflen;
void sub()
{
SOCKET s;
unsigned char *r_msg;
int time;
int cc;
r_msg=(char *)malloc(sizeof(char)*buflen );
cc = sub_recv(s, r_msg, time);
free(r_msg);
・・・
}
void sub_recv(s,*msg,time)
{
unsigned char *pack;
int cc;
int len;
pack = (unsigend char *)msg
/*ここの代入は無意味と思いますがなくしても同様の結果のなので残してます。*/
cc = recv(s, (char *)pack, len, 0);
if(cc < 0)
return(cc);
・・・
}
しかし、このような修正で*r_msgにはrecv()で受け取った内容が入る気がするのですが、
ccには-1が入ってしまい、ifに引っかかって終了してしまいます。
この時のerrnoを見ても104が入り、connection reset by peerといった感じです。
recv()の第二引数にはこれがバッファが用意されてればいいと解釈しておりますが、
これではバッファが1バイトしかとれていないなどあるのでしょうか。
因に、send()がないからというのはありません。
キャストが間違えているなどもあるかもしれませんが、宜しくお願いします。
No.2ベストアンサー
- 回答日時:
そういうものは省略されると想像するしか無いので、正しいかどうかの判断はできないのですが...
変更点は本当にここだけですか?(関数subのr_msgが構造体かunsigned char*かの違い)
変更前と後のソースファイル全部をdiffで比較しても、変更点はここだけですか?
Cのポインタの性質を考えれば、それだけの変更なら動作に違いはないはずです。
ポインタ自体には、実体が何型か、などという情報は含まれていないのですから。特に今回はchar*にキャストしているので、元が何型であったとしても、char*として扱われます。
また、recvは受け取るための関数であって、元に何が書かれていようが関係なく、受け取ったデータをそのポインタに順番に書き込むだけのはずです。
他に変わったんじゃないですか?
通信の仕様が変わって、バッファを可変にする必要がでてきたので、プログラムを変更してるのではないですか?
試しに、変更前のプログラムで 関数subの r_msg だけ変更して実行してみてください。
struct msg* r_msg;
r_msg=malloc(buflen) ;
sub_recv(s,r_msg,time) ;
以下、 r_msg.XXX → r_msg->XXXに変更
そちらでは正常に動作するはずです。
kmeeさん
ご回答ありがとうございます。
省略して申し訳ありませんでした。
>通信の仕様が変わって、バッファを可変にする必要がでてきたので、プログラムを変更してるのではないですか?
通信の仕様は変えていないと思います。
実際は send() で送るバッファも struct msg の構造体だったのですが、これを buflen で malloc した配列に変更しています。
修正しているのは自分だけなので、他は特に変更点はないはずです。
なので、send() 側を可変にしている状態で、recv() 側(今回質問させて頂いているソース)を修正前のソースですと、
struct msg 構造体でとってあるバッファ以下のものは受信できるのですが、当然それ以上だとプログラムが終了します。
なので、質問のような修正を行っております。
単純に recv() の動きを見たいと思い、以下のような事を試してみました。
void sub_recv(s,*msg,time)
{
unsigned char *pack;
int cc;
int len;
char buf[buflen]; //recv() 確認用バッファ。単純化する為に配列。
pack = (unsigend char *)msg
/*ここの代入は無意味と思いますがなくしても同様の結果のなので残してます。*/
cc = recv(s, buf, len, 0); //そのまま recv() に配列 buf を渡す
if(cc < 0)
return(cc);
・・・
}
他の部分で落ちるにしてもとりあえず recv() からは 1~len の値が返ってくるだろうと
期待したのですが、これでも cc には -1 が入ってしまうようなので、困惑しています。
アドバイス頂きましたものを参考に試してみたいと思います。
ありがとうございます。
No.1
- 回答日時:
まず
> void sub_recv(s,*msg,time)
いまどき、こんな宣言は使いません。
別にプロトタイプ宣言がされているのでしょうか?
それとも、コンパイラやライブラリが古い仕様なのでしょうか?
> int len;
とありますが、そのlenに値が設定されていません。
ここに載せるときに省略しただけでしょうか?
そうでないなら、lenの値は不定です。何が入っているかわかりません。
len = 1 となっている可能性も0ではありません。recvの第三引数は、読み取る最大長を指定するものなので、 1バイトしかとれない、ということも有り得ます。
> extern int buflen;
> void sub()
...
> r_msg=(char *)malloc(sizeof(char)*buflen );
こういうのって、void sub(int buflen) と宣言して、引数で渡すのが普通で、externの変数を呼ぶなんてことは、それの方が明らかに便利、というときでもないかぎりやりません。
で、ここで確保した長さであるbuflenは、recvの第三引数として使いたいものではないでしょうか?
> void sub_recv(s,*msg,time)
→
void sub_recv(int s, struct msg *msg,int time,int len) とでも宣言して、
sub_recv(s,r_msg,time,buflen) とでも呼び出すのがいいのではないでしょうか?
> return(cc);
void型関数で値を返してはだめでしょ。
void型ならretrunだけにする。
値を返すなら、適切な型にしましょう。
この回答への補足
kmeeさん
早速のご回答ありがとうございます。
>void sub_recv(s,*msg,time)
ですが、これは
int sub_recv(SOCCKET s, unsigned char *msg, int time)
の間違いです。プロトタイプ宣言を忘れてしまい申し訳ありません。
質問を書いてるうちにccを戻そうと書いたところ、voidの修正も忘れてました。
>とありますが、そのlenに値が設定されていません。
>ここに載せるときに省略しただけでしょうか?
それぞれの変数には任意の値が入っていると仮定して下さい。説明不足で申し訳ありません。
ご指摘有り難うございます。
pack = (unsigend char *)msg
もセミコロンが抜けたりしていてすいません。
>こういうのって、void sub(int buflen) と宣言して、引数で渡すのが普通で、externの変数を呼ぶなんてことは、それの方が明らかに便利、というときでもないかぎりやりません。
おっしゃることは承知ですが、このbuflenをexternで使用したいと思っています。
ご提案のようにsub_recv()にbuflenを引数で渡す場合には、sub()内でなくそちらでmallocした方がいいということでしょうか?
今回伺いたかったのが、r_msgとmsgとpktの関係の部分についてだったので、他の部分を省いてしまったりでわかりずらく申し訳ありません。
なぜ修正後のものだとrecv()から-1が返ってきてしまうのか。そこが知りたいです。
r_msgに適当に文字列を入れてsub_recv()の中で*msgも*pktも期待値が取れるので、アドレスはちゃんと渡せているように思うのですが。
因に、lenに入る値はbuflenよりも小さいものと仮定してください。
わかりにくい質問で大変恐縮ですが、何卒宜しくお願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# C言語 共用体について コマンドライン引数で値を2つ入力したときに、argv[2]の値をUNI u1 4 2022/04/25 20:34
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
fgetsなどのときのstdinのバッ...
-
配列をnビットシフトする
-
CStringをwchar_tに変換したい
-
double型の値をchar配列に変換...
-
コンパイルエラー invalid ope...
-
variant型ってどのような仕組み...
-
strchr() の第2引数はなぜ int ...
-
C++ の FileCopy の設定が解り...
-
int main()の・・・
-
_TCHAR*での引数の読み込み
-
c++ 文字列を入力して、一文字...
-
-'0'の意味について
-
コマンドラインに入力されてい...
-
数字文字の出現回数を表示する...
-
文字列がNULLか空文字列かの判定
-
new
-
sprintfに同じ変数は使えるか
-
間接参照のレベルが異なっています
-
charからLPTSTRへの変換方法
-
c言語
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
fgetsなどのときのstdinのバッ...
-
charでの計算?
-
C言語のfor文です。 繰り返しの...
-
charからLPTSTRへの変換方法
-
文字列から空白を取り除きたい...
-
C言語の入力した文字を反転させ...
-
'const char *' 型は 'char *' ...
-
配列をnビットシフトする
-
str系関数を使わずに二つの文字...
-
int main()の・・・
-
atoi( ) の反対をやりたい
-
CStringをwchar_tに変換したい
-
c++ 文字列を入力して、一文字...
-
switch文で文字を比較すること...
-
干支のプログラム
-
3桁区切(コンマ)記号をつけ...
-
絶対パスからのファイル名の切...
-
間接操作のレベルとは
-
間接参照のレベルが異なっています
-
型変換
おすすめ情報