質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

3341閲覧

C言語でポインタを使わないで参照する構造体のメンバを切り替える方法

ParaParaDance

総合スコア56

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2020/07/02 02:31

編集2020/07/02 02:36

C言語でポインタを使い、構造体メンバを指定する方法はありますが、構造体のメンバの型や入出力型が同じではないと、読み書きが難しいです。

ポインタを使わないで構造体メンバを切り替える方法があればベストですが、やはりC言語では無理でしょうか。 良い方法があればアドバイスをお願いします。

動かないソースではありますが、イメージとしては以下のようです。

typedef struct{ uint32_t a; uint8_t b; uint16_t c; }hoge_m; uint32_t hoge_func(hoge_m *hoge_para, uint8_t select){ uint32_t out; out = hoge_para->( select ); //selectのところにポインタではなく、引数を当てて切り替える。 return out; }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2020/07/02 02:34

「構造体のメンバの型や入出力型が同じではないと、読み書きが難しいです。」とありますが、例では全部uint32_t型です。 そのあたりも含めてもう少しわかりやすく表現していただけないでしょうか?
maisumakun

2020/07/02 02:39

参照すべきメンバの型はどこまでの範囲を考える必要がありますか? ・すべてunsignedな整数型 ・符号付きもありうる整数型 ・浮動小数点型が来るかもしれない ・ポインタも入ってくる
fana

2020/07/02 02:45

何がしたいのかわからない. 「ポインタを使い、構造体メンバを指定する方法」が比較として例示されていると良いと思う.
ParaParaDance

2020/07/02 02:45

データベースは、1か所のみunsignedで、他は全て、uint8_t, uint16_t, uint32だけです。 unsignedは例外として処理すれば、無視しても良いです。 浮動小数点、ポインタはありません。
maisumakun

2020/07/02 02:48

どのような状況でこのような実装が必要となったのでしょうか? (もっと広い視点で見直せば、素直にできる方法があるかもしれません)
ParaParaDance

2020/07/02 02:59

struct構造のdatabaseがあって、外部から1の引数でコールされれば、structのaの値を返す。引数が2であればstructのbを返す。3であればcを返すといった形です。 今は引数をswitchで分岐させ、structメンバを読んできていますが、そうすると、メンバ数分、caseをつくって返す処理になるため、同じ動作をルーチンがたくさんできてしまいます。 そこでstructメンバの値を返すルーチンを共通化したいわけです。
nob.

2020/07/02 03:06

考えつくのは 全部 uint32_t にして、配列にする。 select で指定された配列の要素を返す ぐらいですが、だめですか? 「メンバを選ぶ機能」なので、「メンバを選ぶ動作」は必要な気がします。
退会済みユーザー

退会済みユーザー

2020/07/02 05:41

色々な型が混じっているようですが、そういう関数があったとして、戻ってくる型はどうするんです?
退会済みユーザー

退会済みユーザー

2020/07/02 09:57

構造体のメモリオフセットを自力で計算すれば出来なくはないでしょうが、多分普通に構造体参照するより遥かに面倒くさいです。 C#ならば、リフレクション経由で構造体のメンバを列挙する事も可能なので、C#も検討してみてください。
thkana

2020/07/02 12:15

既にでていますが、全部uint32_tにしてしまったらいけないのでしょうか? struct typedef{ uint32_t a; uint32_t b; uint32_t c; }hoge_m; typedef union{ unit32_t hoge_m[3];//あまり綺麗な気がしないけど、気持ち的にはこういうことをしたいのか、と hoge_m hoge; } hoge_u; とすると不都合がありますか?
ParaParaDance

2020/07/03 04:39

問題はcoltex ARMってことです。 メモリの制限もあるので、全て32bitにしたらその分無駄になります。 色んなご意見有難うございました。
guest

回答3

0

こんなのでお茶を濁すとか.

typedef struct { uint32_t a; uint8_t b; uint16_t c; }hoge_m; uint32_t Get_a( hoge_m *h ){ return h->a; } uint32_t Get_b( hoge_m *h ){ return h->b; } uint32_t Get_c( hoge_m *h ){ return h->c; } typedef uint32_t (*pMemGetFunc)( hoge_m * ); // //※selectの値は {0,1,2} →メンバの {a,b,c} に対応 // uint32_t hoge_func(hoge_m *hoge_para, uint8_t select) { static const pMemGetFunc Funcs[3] = { Get_a, Get_b, Get_c }; return Funcs[select]( hoge_para ); } int main( void ) { hoge_m H; H.a = 4; H.b = 15; H.c = 77; for( int i=0; i<3; ++i ) { printf( "%u\n", hoge_func( &H, i ) ); } return 0; }

別の.

uint32_t Get_Member_value_as_uint32( uint8_t *pStructHead, const size_t *SizeMap, uint8_t select ) { uint8_t *pos = pStructHead; for( uint8_t i=0; i<select; ++i ){ pos += SizeMap[i]; } switch( SizeMap[select] ) { case 4: return *( (uint32_t*)pos ); case 2: return *( (uint16_t*)pos ); case 1: //fall through default: return *pos; } } //----- #pragma pack(push,1) //※環境次第 typedef struct { uint32_t a; uint8_t b; uint16_t c; }hoge_m; #pragma pack(pop) //※環境次第 //↑のstructを実装した人間は, //せめて,このような関数もセットで書くくらいの労力を費やしてもよいのではなイカ? //(あるいはもう機械的に何かで出力すればよくね?) uint32_t hoge_func(hoge_m *hoge_para, uint8_t select) { static const size_t MemSize[] = { 4, 1, 2 }; //各メンバのサイズ return Get_Member_value_as_uint32( (uint8_t*)hoge_para, MemSize, select ); } //-----

投稿2020/07/03 04:54

編集2020/07/03 07:11
fana

総合スコア11996

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/07/03 07:40 編集

メンバ数分switchを書きたくないという事なので、メンバ数分の関数ポインタを定義しなければならず、多分switchより手間が掛かってしまうのではないかと。C言語の範疇では、難しいでしょうねぇ。
fana

2020/07/03 07:17

オフセットとサイズの表くらいは作らないと無理な気がする. それを作るのは人手でなくても良いと思うし. (というか,switchのコードを吐くやつを用意すればよくね?感.)
退会済みユーザー

退会済みユーザー

2020/07/03 07:21

構造体のオフセットとデータサイズを、ビルド時に構造体定義から自動的に計算してテキストファイルに出力する別のプログラム走らせて下の方法で読ませる、なら多少は省力化できそうですね
fana

2020/07/03 07:34

追加した側,メンバ配置をみっちり詰めてるんだから,メンバのサイズじゃなくてオフセットのテーブルにした方が良いですね. サイズはテーブル要素から引き算で求まるので.
guest

0

、メンバ数分、caseをつくって返す処理になるため、同じ動作をルーチンがたくさんできてしまいます。

そこでstructメンバの値を返すルーチンを共通化したいわけです。

マクロ展開するのが妥当かと思います。

投稿2020/07/02 03:00

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

こんにちは。

C言語の場合は、hoge_para_uint32(), hoge_para_uint8(), hoge_para_uint16()的な関数を用意して注意深く呼び分けるのが一般的と思います。(暗黙の型変換に要注意)

C++は、それのような要求に対するサポートがあります。関数のオーバーロードと呼ばれています。
ただし、暗黙の型変換による落とし穴もあるので使い方は要注意です。特に整数型同士での呼び分けは意外に深い落とし穴が開いています


【追記】
「質問への追記・修正」依頼欄を見落としていました。
uint32_t型で全て返すことが目的なのですね。1, 2, 3的な番号(メンバ変数ID?)を指定して、該当のメンバの値を返したいと。
番号→メンバ変数変換が必要になりますので、switch-caseを使わざる得ないと思います。(番号が定数なら他にも考えられますが、定数でよいなら変数名でも良いはずなので意味はないです。)

そこでstructメンバの値を返すルーチンを共通化したいわけです。

その共通化ルーチン内でswitch-caseするしかないだろうと思います。

投稿2020/07/02 02:57

編集2020/07/02 03:12
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問