ネットワークプログラミングを勉強しているのですが,ソケットを用いた通信のサンプルで,
HOSTENT *lphost
として,HOSTENT構造体へのポインタを宣言して,
lphost = gethostbyname(ホスト名の文字列);
で,サーバーのアドレスをHOSTENT構造体にセットするとあります。
構造体へのポインタを宣言しても,構造体自体の領域は確保されないのではないかと思うのですが,gethostbyname関数が返すポインタは,いったい誰がどこに確保した領域を指しているのか,そしてその領域はいつまで保持されるのか,よく理解できません。構造体そのものを宣言せずに,それへのポインタを宣言し,それに関数の戻り値を代入するというのが,よく理解できないです。どなたか解説していただけると幸いです。
No.2ベストアンサー
- 回答日時:
★アドバイス
>おおもとのmain関数が終了するまで値を保持し続ける
↑
そうです。
ただし複数回gethostbyname関数を呼び出すと最後の情報だけが
構造体の値として残ります。よって複数回呼び出す場合は
構造体へコピーして使う必要があります。
※1回しか呼び出さないならポインタで使いまわせば良い。
// 構造体を宣言
HOSTENT host;
// 構造体をコピー
host = *gethostbyname( ホスト名の文字列 );
このように戻り値のポインタを使って別々の構造体にコピーすれば
マルチスレッドや複数回呼び出しにも対応できます。
※C標準関数のlocaltime関数の仕組みと同じです。
※内部にstaticな構造体を1つだけ持っていてそのポインタを返す。
※http://www9.plala.or.jp/sgwr-t/lib/localtime.html
ご回答ありがとうございます。
呼び出し元で構造体を用意して,それへのポインタを関数に渡して,構造体にデータをセットしてもう場合と,関数が構造体を用意して,それにデータをセットして,その構造体へのポインタを返す場合があるのですね。必要に応じて,呼び出し元が構造体を用意して,関数の用意した構造体の値をコピーして使う。
どうして関数によって処理の仕方が違うのでしょうか。これらの違いには何か理由があるのですか。
No.3
- 回答日時:
No.1 です。
「どうして関数によって処理の仕方が違うのでしょうか。これらの違いには何か理由があるのですか。」
特に理由なんてないのではないでしょうか。最初に作った人が適当に(今となっては良くない)仕様を決めてしまっただけだと思いますよ。10 年以上前に作られたんではないでしょうか。
Linux や Unix ではこのような例がいくつも見られて、例えば errno というグローバル変数は、今の時代当たり前のマルチスレッドでは実は困り者なんですが、なんとかコンパイラで誤摩化してしまっています。
私の最初の回答では、マルチスレッドで問題になると書きましたが、マルチスレッドでなくても、2回以上、gethostbyname() を呼ぶと、最初に帰って来た値が次の呼び出しの値に書き換えられてしまうため、最初に帰って来た値が突然変わってビックリすることもあります。
いまひとつ自信がないんですが、No.3 さんのご回答にあるような方法で、構造体をコピーしてもダメだと思います。つまり HOSTENT 構造体のメンバーの文字列もコピーしなくてはなりませんから。このように構造体の全てのメンバー(もしメンバーが構造体だったらそのメンバーも)全てコピーする事を deep copy といったりします。で、HOSTENT をコピーするなら deep copy でないとダメですね。
実際、gethostbymae_r() 関数は deep copy をしてくれるんですが、HOSTENT の全てのメンバーの文字列領域を gethostbyname_r() 関数に別途与える必要があって、面倒なのです(全ての文字列を格納するに必要なだけの長さが事前に分からないので)。
No.1
- 回答日時:
OS が分からないのですが、以下 Linux と仮定して。
参考 URL に Linux の man page を示しました。ここに書いてあるように、gethostbyname() は内部に static 宣言された struct hostent の構造体へのポインタを返します。あるいは、実装によってそういう場合があるので、例えば、帰って来た struct hostent を free() する、なんてことはしてはいけません。
さらに、この仕様は pthread 等で並行的に動作する場合、正しい動作が保証されません。このため Linux では gethostent_r() という関数があって、再帰呼び出しを可能にしています。ただし、この関数は、元の gethostent() をベースにしているので使い難いのが難点です。
Linux というか Unix には仕様自体が古くて、最近のマルチスレッドでは使う事ができない関数というのがいくつか存在します。たとえば strtok() もそのひとつです。これらの関数では関数内部の static 変数に状態を保存してしまっていますので、再帰呼び出しができない構造になっているのです。
参考URL:http://www.linux.or.jp/JM/html/LDP_man-pages/man …
ありがとうございます。
猫でもわかるシリーズをC言語編,Windows編,ネットワーク編と読み進めてきた初心者です。VC++を使うつもりです。
ということは,呼び出されたgethostbyname関数が構造体を静的に宣言して,その構造体へのポインタを返し,それはstaticなものなので,おおもとのmain関数が終了するまで値を保持し続けるという理解でよいのでしょうか。
マルチスレッドのことはよくわからないですが,gethostbyname関数は,一つの同一のHOSTENT構造体にデータをセットするので,複数のスレッドからgethostbyname関数を呼び出すと,それぞれが関数を呼び出すたびに異なる値が構造体にセットされ,とんでもないことになるということですか。
なんとなくわかったような気がします。ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語で構造体の参照渡しができません 2 2022/12/18 21:22
- C言語・C++・C# ポインタの型変換、どうやるんでしたっけ? 2 2022/03/28 11:00
- 哲学 説得力を修辞の巧みさまたは論理の強さの2つに分析するにはどうすると良いでしょうか? 0 2022/07/20 05:46
- C言語・C++・C# いまc言語を独学で勉強しているのですがいまいちわかりません。 https://monozukuri- 3 2023/07/06 18:59
- C言語・C++・C# C言語の質問です。 以下の命令を実行するプログラムを作りました ①文字列aとbの長さを表示 ②aとb 1 2022/04/29 15:35
- C言語・C++・C# C言語初心者 構造体 課題について 1 2023/03/10 19:30
- C言語・C++・C# C言語 ポインタ 配列 2 2022/06/02 17:29
- C言語・C++・C# c言語 コマンドライン引数 4 2023/02/09 18:47
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# 競技プログラミングに関する質問です。 3 2022/04/03 19:51
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語のポインタに直接アドレス...
-
セグメントエラー
-
fopne で失敗する原因
-
c言語で任意のファイルから読み...
-
C言語でのconstを返す関数
-
【なぜポインタを使うのか】
-
main(int argc,char **argv[])...
-
nullポインタを逆参照とは?
-
構造体を値で渡す良い点はあり...
-
【C言語】戻り値が構造体の関数
-
関数ポインタの高速化のメリット
-
自作strcat
-
アプリを32bitから64bit移行
-
popenした子プロセスのプロセス...
-
C言語によるメモリ読み書き
-
JavaとC++はどう似てる?
-
ハンドル、アドレス、ポインタ...
-
c言語のポインタについて初心者...
-
キャストについて str = (CStr...
-
リトルエンディアンというもの...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
セグメントエラー
-
C言語のポインタに直接アドレス...
-
fopne で失敗する原因
-
init関数の意味
-
Run-Time Check Failure #3とい...
-
戻り値で構造体を返すことは可...
-
LPSTR型の初期化について
-
Cで作成したDLL関数をVBから呼...
-
ExcelVBAでのkernel32(64bit)
-
アプリを32bitから64bit移行
-
構造体とfscanf
-
c言語で任意のファイルから読み...
-
デバイスハンドルとは?
-
main(int argc,char **argv[])...
-
基本アルゴリズムの『返す』の...
-
コンストラクタでnewを失敗した...
-
C言語の関数と配列に関する質問
-
参照型で受け取った引数をポイ...
-
ハンドル、アドレス、ポインタ...
-
DLL<->VB間での受け渡し(文字...
おすすめ情報