• ベストアンサー

構造体でデータをやり取り出来ないか

 みなさん、こんにちは。質問させて頂きます。  関数に変数を渡すとき、変数のポインタを渡す方法が有ります。  この方法なら呼ばれた関数が、呼び出した関数の変数を直接操作出来ます。  これを構造体で出来ないでしょうか。  下記のプログラムで実験しました。(2)の所を色々と書き換えて試したのですが、エラーになります。  (1)は、エラーになりません。エラーで無く(2)の様に使えなければ、(1)の p はどのような使い道が有るのでしょう。 /*-----------------------------*/ struct Par { long a ; } ; /*-----------------------------*/ void sub1( struct Par *p )  ・・・(1) エラーにならない { p.a = 2 ;   ・・・(2) 色々変えて試しても、エラーになる }

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

  • ベストアンサー
  • jgk
  • ベストアンサー率75% (104/138)
回答No.1

構造体のポインタへの各要素のアクセスにはアロー演算子を使用します。 p->a = 2; 変数のポインタと同じ用に*p.a = 2;も試したと思いますが、 こういう表記をする場合の場合、 (*p).a = 2; という表記になります。

ricardo_
質問者

お礼

 有り難う御座います。この方法で解決しました。  「(*p).a = 2; 」も試したような気がするのですが、試していなかったようです。  構造体内の変数を増やして実験しました。アセンブル結果を見ると、期待通りの結果が得られました。変数はスタック領域に確保されていました。  実はアセンブラで書いたプログラムを、C言語に焼き直しています。  変数をレジスタ渡しで巧妙に作って有るのですが、レジスタの管理が面倒です。  C言語で書けばプログラムは長くなり、実行速度は遅くなると思いコンパイル結果を見て評価しています。  変数が少なければコンパイラはレジスタ渡しにするかなと思い実験しましたが、スタック領域を使っていました。  「C言語で可能な事、不可能な事」が一つ分かり、勉強になりました。  どうも有り難う御座いました。

その他の回答 (4)

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.5

> 変数が少なければコンパイラはレジスタ渡しにするかなと思い実験しましたが、スタック領域を使っていました。 レジスタ渡しが有効なほど小さい関数なら、inlineが有効だと思います。 inlineが意味を持たないようなサイズの関数なら、せっかくレジスタ渡しにしても全体の高速化には貢献しないと思います。 C/C++の場合、人間があれこれ最適化を考えるよりも、いかにしてコンパイラに最適化をさせるかというテクニックが重要だったりしますね。 あと、static関数だと、呼び出し規約に縛られないので、レジスタ渡しに最適化してくれる可能性もありそうです。

ricardo_
質問者

お礼

 回答有り難う御座います。  inline と static関数に付いて調べていたので、お礼が遅くなりました。  プログラム分割のために1箇所からしか使わない関数が多いので、inline は勉強になりました。  include で挿入した事も有ります。  static は変数だけでなく、関数でも使える事が分かりました。  有り難う御座いました。また質問したときは、宜しくお願いします。

  • chie65535
  • ベストアンサー率43% (8517/19361)
回答No.4

>変数が少なければコンパイラはレジスタ渡しにするかなと思い実験しましたが、スタック領域を使っていました。 >「C言語で可能な事、不可能な事」が一つ分かり、勉強になりました。 「コンパイラ任せ」になってしまいますが、関数内で宣言する変数にregister修飾子を付加すると、高速なコードを生成する場合があります。 例: void sub(int para1,int para2) { register int eax = para1; register int ecx = para2; … 但し「場合がある」と言うだけなので「付けても付けなくても一緒」の場合もあります(例えば、速度最優先の最適化オプションを指定してコンパイルした時、など)

ricardo_
質問者

お礼

 御回答有り難う御座います。  構造体に「register」は使えないだろうと思い実験してみましたが、 やはりエラーになりました。  三菱か何処かのCコンパイラの説明書に、「変数のアドレスが存在しないから、「&」が使えなくなるだけで、積極的にCPUのレジスタに割り当てる事はしていない」と言うような説明でした。

  • php504
  • ベストアンサー率42% (926/2160)
回答No.3

関数への引数の渡し方は呼出規約で決まっているため数が少ないからレジスタで渡すとか変わることはありません VisualC++なら呼出規約のfastcallを使えばレジスタ渡しになったと思います http://ja.wikipedia.org/wiki/%E5%91%BC%E5%87%BA%E8%A6%8F%E7%B4%84

ricardo_
質問者

お礼

 回答有り難う御座いました。  「呼び出し規約」と言うのを初めて知りました。

  • asuncion
  • ベストアンサー率33% (2126/6287)
回答No.2

#1さんの補足です。 *p.a と書くと、*よりも.の方が優先順位が高いので、 *(p.a) という意味となります。 (*p).a と p->a とが同じ意味です。

ricardo_
質問者

お礼

 asuncion さん、有り難う御座います。  パラグアイのアスンシオンに居たことが有るので懐かしいな。 >(*p).a と p->a とが同じ意味です。  アロー演算子を見た事は有るけれど、意味を深く考えた事が無かったので勉強になりました。 オパ! (パラグアイのグアラニー語で、「お終い」と言う意味)

関連するQ&A

  • 構造体の配列を関数に渡すには

    構造体の配列を関数の引数として渡そうとすると エラーになってしまいます ネットで調べてもいまいちわからなかったので ここで質問させてもらいます #include<stdio.h> struct A{   ・    ・    ・ }; void func(struct A *p); int main(void) { struct A x[3][4] = {     ・     ・     ・ }; func(x); return 0; } void func(struct A *p){     ・     ・    ・ } どうすれば渡すことができるのでしょうか? どなたか助言お願いします。

  • 構造体の纏め方

    関数のポインタを使用して、 /* プロトタイプ宣言 */ void func1 ( void ); void func2 ( void ); void func3 ( void ); /*******************/ /* プロトタイプ纏める */ void ( *funcs[] ) ( void ) = { func1, func2, func3 }; /*********************/ と言うのが、構造体でも出来ないでしょうか?と言うのが質問です。 変数(添字)によって、見るべき構造体を自由に変更させたいと言うのが主な使用方法です。 typedef struct _tag { int arg1; int arg2; } tag; tag watch1 , watch2 , watch3; とある変数が1なら、watch1、とある変数が2なら、watch2、とある変数が3なら、watch3を見ると言うようなプログラムにしたくて、質問しました。 witch文を使うしかないのでしょうか? 良き回答、お待ちしています。

  • ポインタを使った構造体のプログラム

    ポインタを使ってメンバに値を入力して表示するプログラムを作ったのですが、mainのstruct XYZ aというオブジェクトと*bというそれを指すポインタを使ってプログラムを表示するにはどうすればいいのでしょうか。 これがプログラムです。 #include <stdio.h> struct XYZ { int x; long int y; double z; }; void set_xyz(struct XYZ *p,int x,long int y,double z) { p->x=x; p->y=y; p->z=z; } //void set_xyz(struct XYZ *,int,long int,double); int main() { struct XYZ a = {12,999999,1.41421356},*b; //ここのポインタ変数bでエラーが表示されます。 set_xyz(b,a.x,a.y,a.z); printf("a.x = %d\na.y = %d\na.z = %lf\n",b->x,b->y,b->z); return 0; } エラーの内容は「初期化されていないローカル変数 'b' が使用されます」となっています。 初歩的な質問ですみません・・・。

  • ポインタを使って構造体の配列を戻り値にするには

    関数の戻り値を構造体の配列(アドレスを受け渡しを利用して)にしたいのですがうまくゆきません。 以下のプログラムではコンパイルはできるのですが、 a0 = 2 a1 = 4198512 a2 = 4329332 と表示されてしまいa1,a2がうまくゆきません。 ********************************************* #include<stdio.h> struct test{ int a; }; struct test *func(void); void main(void) { struct test *data;//構造体ポインタ int i; data = func(); //ポインタにtest関数の戻り値(アドレス)を代入 for(i=0;i<=2;i++){   printf("a%d = %d\n",i,(data+i)->a); //構造体要素を表示 } } struct test *func(void) { struct test data[3]={1,2,3}; //構造体配列を定義 return (&data[0]); //構造体配列の先頭アドレスを返す } ************************************************* test関数から受ける取ったアドレス(&data[0])をポインタ(data)に代入して1づつずらして表示させれば a0=1,a1=2,a=3 となると思ったのですがどこが間違っているのでしょうか? よろしくお願いします。

  • ポインタ型配列のポインタを構造体のポインタ変数に格納する方法教えて!_ver2

    int型の配列は構造体のポインタ型のint型変数にはキャストすればうまくコンパイルが通りますが、同じ方法でfloat型の配列は構造体のポインタ型のfloat型変数にはキャストしてポインタの値を入れてもうまくコンパイルできず困っています。ちなみにコンパイルエラーは「互換でない型変換」と表示されます。 返答のほど、よろしくお願いいたします。 #include<stdio.h> #include<malloc.h> float time[] ={2.2, 2.3, 2.4}; int time2[] ={2, 2, 2}; struct timelist{ float *time; int *time2; struct timelist *next; }*head; void main(void) { struct timelist *p; p = (struct timelist *)malloc(sizeof(struct timelist)); p -> time = (float *)time[0]; p -> time2 = (int *)time2[0]; printf("time = %f\n", p -> time); printf("time2 = %d\n", p -> time2); }

  • 構造体を指すポインタからその中のポインタ変数が指す要素の参照

    構造体を指しているポインタから、 その構造体内にあるポインタ変数の指している要素に値を代入する方法が、どうしてもわかりませんでした。 どなたか助けてください、お願いします。 struct Kouzou { int* p; }; int main() { Kouzou kou; Kouzou* k_p; k_p = &kou; k_p -> *p = 10; //エラー }

  • 構造体を引数とする、クラス間のデータの受渡し方法について

    現在、C++の構造体を理解しようと努めていますが、どうしても理解できない点があり、 なにとぞ、ご指導・ご助言のほどよろしくお願い致します。 1.質問内容  a.構造体を引数とする、クラス間のデータの受渡し方法について ・主プロ(主クラス)側の構造体のメンバ変数を、サブプロ(サブクラス)側で更新するのに、 メンバ変数を一つずつ引数として渡せば、正しく更新できるのですが、構造体を引数として渡すと    コンパイルエラーになります。   ・どのように定義すれ場良いのかをご助言お願い致します。 2.プログラムの内容を簡単に記載します。  全部を記載する事は出来ないので、一部を省略して簡単に必要な所だけを記載します。  a.Main.cpp int main() { CMain main; CSub sub; //Main_Classの関数に、Sub_Classクラスのポインタを引数として渡し、Sub_Classクラスの関数を呼び出す main.Main_FuncCall(&sub); return 0; } b.CMain_Class.h class CMain { public: //コンストラクタ 省略 //デストラクタ 省略 typedef struct CHAR1 { int m_chx; int m_chy; bool m_chValidFlag; }; CHAR1 *pc; //データの受け渡し(ポインタ) void Main_FuncCall( CSub* cs ); };  c.CMain_Class.cpp void CMain::Main_FuncCall( CSub* cs ) { //メインクラスの構造体を引数として、サブクラスの関数を呼び出す //サブプロ側の構造体を更新する cs->Sub_FuncCall4( pc ); } d.CSub_Class.h class CSub { public: //コンストラクタ 省略 //デストラクタ 省略 typedef struct CHAR_S { int m_chx; int m_chy; bool m_chValidFlag; }; CHAR_S *ps; void Sub_FuncCall( CHAR_S *pc ); }; e.CSub_Class.cpp void CSub::Sub_FuncCall( CHAR_S *pc ) { pc[1].m_chx += ps[1].m_chx; } 3.コンパイルする  a. cs->Sub_FuncCall4( pc ); -> 1 番目の引数を 'struct CMain::CHAR1 *' から 'struct CSub::CHAR_S *' に変換できません。 (新しい機能 ; ヘルプを参照) 指示された型は関連がありません; 変換には reinterpret_cast、 C スタイル キャストまたは関数スタイルのキャストが必要です。 b.色々と試してみましたが、現在の私の知識ではコンパイルができません。   アドバイスのほど、よろしくお願いします。

  • void型のポインタで構造体の参照

    void型のポインタで構造体や共用体を参照することはできますか? void *p=&kou; struct KOU kou; (struct KOU*)kou.name="名前"; のようにして構造体を参照しようとしたのですが、「左側が構造体又は共用体ではありません。」と出ます。型キャストはコンパイラに型を知らせるだけのものなのでコンパイラが構造体の型を知ることができない、ということでしょうか?void型のポインタを使って構造体(共用体)を参照することはできますか?回答よろしくお願いします。

  • C言語の構造体についてなんですが。

    struct LIST {     struct Num* number;     struct LIST* next;/* 次の要素へのポインタ */ }*root; struct Num{     int a;     struct Num* next; /* 次の要素へのポインタ */ }*numroot; と構造体を定義したときに、 main(){     struct LIST *p;     for(p = root; p != NULL; p = p->next) ; } とすれば、pの先頭からNULLまでを参照していくことは分かるんですが、pのnumberの先頭からNULLまでの参照方法(プログラムのfor文の記述方法)がイマイチわかりません。つまり、構造体の構造体をどのように参照するかということです。 これを実現したい理由は、構造体内での数の格納を配列(固定長)ではなく可変長で格納したいからです。 分かる方は解答をお願いします。

  • 構造体の使い方

    構造体が定義されている場所では、 struct runqueue{ task_t としかないのに、実際の関数の部分では task_t *p = current というように、変数として宣言されている部分があるのですが、これにはどういった意味があるのでしょうか?

専門家に質問してみよう