• ベストアンサー

値を返さないといけないのに、返さない関数の挙動

こんな感じの構造体・関数を作ったとします。 typedef struct personal_info {    char name[10];    char address[20]; } personal_t; personal_t getPersonal(int id){;} これには2つのギモンがありまして 1.getPersonalの中は何もせず、値を返さないのに なぜか、コンパイルは通る 2.実行すると、正常に動く いったい、どういう事なのでしょうか。 不思議でたまりません。 どうぞよろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

すでに回答が出ているように、return文で値を返していないときに、呼出し側で返却値を使った場合の動作は未定義です。 問題はここからで、正常動作する可能性は4パターンです。 1. 返却値を捨てている。 2. 返却値を使ったが、コンパイルエラーになることも、シグナルが発生することも、その他実行時エラーが生じることもなく、値がたまたま期待通りであったか、悪い影響を受けるような使い方をしなかった。 3. 処理系が独自仕様として、正常な動作を定義している。 4. 関数を定義しただけで、呼出していない。 質問の文面からすると、おそらく4.に該当するのではないかと思います。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

回答No.3

では、ちょっとだけ補足をば。 > その振る舞いは未定義である これを、普通の言葉で言い換えたのが、 「どうなるかはそれぞれのコンパイラ毎に異なる」 になります。 もっとも、「処理系依存」も言い換えると同じ表現 になるので、不親切ではありましたが。 なので、紹介したものは、「あくまでも例」であり、 「こういう動作をした場合」なわけです。 そして、それは、「見かけ上正常に動作した」だけ でもあるわけです。 もちろん、 >一見正常に動作しているように見えても、全く問題 > ありません。 は、このコードが「一見正常に動作しているように見 えても」そのコンパイラは、規格に合致していないと いうわけではなく、「全く問題ない」という意味です。 一見……に見えても、って、「じつはそうじゃない」 という表現なので。

全文を見る
すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

ちと ISO を見てみましたが, 「関数の終了の } に到達した (= return 文で何も返さない) ときに, その関数の値を呼び出した方で使ったらその振る舞いは未定義である」 と書いてあります>#1. だから, ここで「正常に動いた」というのは ・返り値を使っていない ・ゴミが入ってるけど結果的に問題なかっただけ の 2通りが考えられます. コンパイルは通るかもしれんけど, 警告くらい出てないかなぁ.

全文を見る
すると、全ての回答が全文表示されます。
回答No.1

それはそういうものだからです……というのが、答えになる のですがそれではあんまりなので。 まず、コンパライラが指摘するエラーは、単に、「文法上の」 エラーに過ぎません。 今のところ、「意味上の」誤りは指摘しません/できません。 この場合、 personal_t getPersonal(int id){;} を見る。 ・personal_t という型は事前に正しく定義されている。 ・関数の宣言として正しい形をしている。 ・関数の実体は、{} で正しく囲まれている ・関数の中身は、 ; という文法的に正しいもの(空文)で  構成されている と、形の上では正解なのでエラーにはなりません。 (警告は出たかもしれません) また、値を返すべき関数が値を返さないときにどうなるかは それぞれのコンパイラ毎に異なるので、一見正常に動作して いるように見えても、全く問題ありません。 具体的な実装では、以下のような例があります(あくまでも例です) ・呼び出し側  1)返値である personal_t 型のサイズの領域を確保する   (ここに、関数が返却値をセットする)  2)関数を呼び出す   ・関数側  1)本来であれば、呼び出し側が確保した領域に、結果を    セットする。今の場合は何もしない     ・再び呼び出し側  1)関数の処理が終わったので、あらかじめ確保した領域に    関数からの返値がセットしてあると信じる  2)その領域(今は、何もしてないのでゴミがたまっている)    の内容を、変数にコピーするなどして引き取る。  3)その領域を、解放する このような処理を行った場合、見かけ上は無事に動いているよ うに見えるわけです。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 構造体型のポインタ変数を含む構造体

    struct seiseki_tag { Int32 math ; Int32 english ; Int32 science; } ; typedef struct seiseki_tag SEISEKI ; struct personal_tag { Char name ; Int32 num ; SEISEKI *sptr } : typedef struct personal_tag PERSONAL ; struct info_tag { PERSONAL person_info ; } ; typedef struct info_tag INFO ; たとえば、上記のように3つの構造体があり、PERSONAL構造体のメンバーに SEISEKI構造体の型を持つポインタ変数が含まれているような場合で、下記のように INFO型のポインタ変数からSEISEKI構造体のメンバーを参照する方法を教えてください。 PERSONAL構造体メンバーのnameやnumは INFO *info ; info->person_info.name ; info->person_info.num ; のように参照すると思いますが、sptrが示すSEISEKI構造体のメンバーへの アクセスができません。下記のように参照を試みたのですがコンパイルは 通るのですが、実際に参照できていませんでした。 INFO *info ; SEISEKI *seiseki ; seiseki = info->person_info.sptr ; seiseki->math ; 判りにくい説明で申し訳ありませんが、どなたか教えていただければと思います。 よろしくお願いいたします。

  • 関数マクロの書き方

    #difine GET_INFO(data) \ do{\ char* addr = topaddr + sizeof(int);\ memcpy(&data,addr,sizeof(int)); \ while(0) 取得さきのメモリのデータ構造は typedef struct _data_t{ int data[2] }data_t data_t test; メモリ上のデータの先頭アドレスはtopaddrとなっている状態で test.data[1] の値を取得する関数マクロの定義としてGET_INFOの書き方は 間違っていますでしょうか?

  • 構造体内のポインタのポインタについて

    ポインタを理解するために以下のようなテストプログラムを作りました。 test.h --- typedef struct i_info{ int i_id; char i_name[64]; } I_INFO; typedef struct j_info{ int j_id; char j_name[64]; } J_INFO; typedef struct k_info{ int k_id; char k_name[64]; } K_INFO; typedef struct info{ int id; char name[64]; I_INFO iinfo; J_INFO *jinfo; K_INFO **kinfo; } INFO; --- test.c --- 1 #include <stdlib.h> 2 #include <stdio.h> 3 #include "./test.h" 4 5 int main(int argc, char **argv) 6 { 7 INFO info; 8 J_INFO j; 9 K_INFO k; 10 K_INFO *pk=NULL; 11 12 memset (&info,NULL,sizeof(info)); 13 memset (&j,NULL,sizeof(j)); 14 memset (&k,NULL,sizeof(k)); 15 16 info.id = 1; 17 memcpy(info.name,"***",3); 18 19 info.iinfo.i_id = 2; 20 memcpy(info.iinfo.i_name,"*i*",3); 21 22 info.jinfo = &j; 23 j.j_id = 3; 24 memcpy(j.j_name,"*j*",3); 25 26 info.kinfo = &pk; 27 pk= &k; 28 k.k_id = 4; 29 memcpy(k.k_name,"*k*",3); 30 31 printf( "%d\n",info.id); 32 printf( "%s\n",info.name); 33 printf( "%d\n",info.iinfo.i_id); 34 printf( "%s\n",info.iinfo.i_name); 35 printf( "%d\n",info.jinfo->j_id); 36 printf( "%s\n",info.jinfo->j_name); 37 /* 38 printf( "%d\n",info.kinfo->k_id); 39 printf( "%s\n",info.kinfo->k_name); 40 */ 41 } --- 38,39行目をコメントアウトするとコンパイルは通るのですが、 そのままだとコンパイルエラーになります。 なぜいけないのでしょうか?理由を教えてください。

  • 構造体についてです。

    typedef struct student{ int id; char name[20]; int kokugo; int sansu; int eigo; }STUDENT; と、 struct student{ int id; char name[20]; int kokugo; int sansu; int eigo; }; の違いはなんでしょう? 私は下記をよく使うのですが・・・。 typedefについて詳しく知りたいです。

  • 配列を含んだ構造体への値設定について教えて下さい。

    配列を含んだ構造体への値設定について教えて下さい。 下記のような構造体の定義があります。 typedef struct A_T { UINT64 a1; UINT32 a2; } A_t; typedef struct B_T { UINT32 b1; A_t b[8]; } B_t; 構造体B_tを関数の引数で渡し、A_tのa1とa2に値を設定したいのですが、プログラミング初心者の為、どのように作ればよいのかわかりません。 どうぞ教えて下さい。

  • 構造体メンバ及び、strncpy()について

    /* 構造体のメンバを char name[30]; にした時は実行できますが、char *name; としたときはプログラムを実行できません。 コンパイルエラーはともに出ないのですが、strncpy();の使い方が間違っているのか、先に構造体側でメモリサイズを確保しないと、使えないのか? メンバをポインタで持たせた構造体を初期化する関数の作り方を教えてください。 よろしくお願いします。 */ #include <stdio.h> #include <string.h> typedef struct{ char *name; int no; }ST; void set_name(ST *st, char *name, int no); int main(void) { ST st; set_name(&st, "テスト", 1); printf("%s No%d\n", st.name, st.no); return 0; } void set_name(ST *st, char *name, int no) { strncpy(st->name, name, 30); st->no=no; }

  • 入れ子になっている構造体配列の初期化がうまくいきません。

    入れ子になっている構造体配列の初期化がうまくいきません。 どのようにすればうまくいくでしょうか? #include <stdio.h> typedef struct _item { int no; char name[10]; int price; }ITEM; typedef struct _all_item_info { ITEM ruit[2]; ITEM vegetable[2]; }ALL_ITEM_INFO; ALL_ITEM_INFO all_item_info = { {1, "apple", 100}, {2, "melon", 80}, {3, "tomato", 100}, {4, "radish", 200} }; int main() { ・・・・ } コンパイルすると、以下のようにエラーになってしまいます。 エラー E2225 kouzoutai7.c 20: 初期化子が多すぎる エラー E2141 kouzoutai7.c 22: 宣言の構文エラー エラー E2190 kouzoutai7.c 22: 不要な } エラー E2190 kouzoutai7.c 22: 不要な } OSはwindows、 コンパイラはBorland C++ Compilerです。

  • 構造体の返し方

    こういう構造体があるとして、 typedef struct Day{  int day1, day2, day3; } Day; このような関数で値を入れて、 int DayTest (char s) {  Day day;  day1 = 2003;  day2 = 12;  dat3 = 31;  return < ここの返し方がわからない >; } これを main() 関数で参照できるようにするには どうすればいいのでしょうか。 printf で出力させるとかで結構です。 ポインタだとは思うのですが、うまくいきません。

  • 構造体へのポインタ

    typedef struct str_tmp_t{ int a; char b; } str_tmp; void main() { str_tmp *str_info; str_info->a = 1; } とした場合、コンパイルエラーは出てはいないのですが、数値を代入している個所で落ちてしまいます。 これを回避するには単純にmallocしてfreeすれば良いのでしょうか? よろしくお願い致します。

  • [C言語]ソート関数の作成

    現在受け取った構造体を受け取ってソートしてポインタで書き換える関数を作成しています。 構造体の配列 typedef struct{ char name[50]; int age; }member; member seito[10] strcpy(seito[0].name,"yamada") seito[0].age = 15; strcpy(seito[2].name,"ito") seito[2].age = 17; strcpy(seito[3].name,"saito") seito[3].age = 19; こちらの構造体は例です。 seito[2]の情報を[1]に seito[3]の情報を[2]に移動させたいのですが、上手くいきません。 構造体配列を、1引いてあげれば良いと思ったのですが、そうすると[0]までマイナスしてしまい上手く判定が出来ません。 どうかアドバイスお願いいたします。