ページ 11

龍神録プログラミングの館の.h記述手法で構造体を使った場合のwarning C4091について

Posted: 2014年1月16日(木) 13:05
by ぱんにゃあ
(開発環境はVisual Studio VC++ 2010です)

extern 宣言をGLOBALとして、プリプロセッサ処理でexternの有無を分ける手法( http://dixq.net/rp/5.html )がありますが、
この手法で構造体をヘッダファイルに直接記述した場合、

コード:

GLOBAL struct Icon{
	int picon;
};

GLOBAL struct Menu{
	int bg;
	int bgb;
	int bgs;
};

GLOBAL struct Texture{
	int item_mask;
};

GLOBAL struct GameGraphics{
	struct Icon icon;
	struct Menu menu;
	struct Texture tex;
};

GLOBAL struct GameData{
	struct GameGraphics pic,alpha;
}data;
warning C4091: 'extern ' : 変数が何も宣言されていないときは、'GameGraphics' の左辺を無視します。

という警告が出てしまいます。
そして、ビルド時にはなぜか出力されませんが、先ほどのコードの data の部分にエラーなどを示す赤波線が表示され、そこにカーソルを合わせると

Error: 宣言に"GameData data" (宣言された 行 x 、ファイル名"ヘッダファイルパス") との互換性がありません

というエラー表示( x は data が記述されている行番号)が出てしまいます。

前者のバグは、 ネストされる予定の構造体に付けたGLOBALがexternになり、実体のない構造体をexternしていたことによる警告ということが特定でき、struct GameData以外のGLOBALを削除することで解決しましたが、後者のバグは原因が特定できません……。

なぜこのような表示が出るのでしょうか・・・><

Re: 龍神録プログラミングの館の.h記述手法で構造体を使った場合のwarning C4091について

Posted: 2014年1月16日(木) 13:19
by Rittai_3D
http://dixq.net/forum/viewtopic.php?f=3&t=2471
の2番目の御津凪さんの返信を参考にして下さい。

extern をつけるのは実体じゃないのでしょうか。

Re: 龍神録プログラミングの館の.h記述手法で構造体を使った場合のwarning C4091について

Posted: 2014年1月16日(木) 13:36
by usao
参考先のやってることを真似る前に,externとは何なのか,
(externの役割は何で,どういうときに,どこに書くべきものなのか)
という点をしっかり理解された方がよいと思います.
で,その上で,「そのページのやっているようなことを真似るべきかどうか」をしっかりと判断されるのがよいかと.
オフトピック
個人的には,そのページでやってるようなことは 絶対やりたくないというか,ある種ばかばかしさすら感じる.
どうしてもexternを使いたいのだとしても,単にextern宣言だけをまとめたヘッダを用意すれば
「変数定義がどれなのか自分でもわかりませんw」なんていう謎状況は生まれないと思うのだが…?

Re: 龍神録プログラミングの館の.h記述手法で構造体を使った場合のwarning C4091について

Posted: 2014年1月16日(木) 14:59
by ぱんにゃあ
3D_3D さんが書きました:http://dixq.net/forum/viewtopic.php?f=3&t=2471
の2番目の御津凪さんの返信を参考にして下さい。

extern をつけるのは実体じゃないのでしょうか。
構造体末尾 } ; の中身が空の、実体のない構造体(ネストするだけなので他のファイルから呼ばない構造体)にGLOBAL(メインcppファイル以外から呼ばれた場合は自動でexternになる)を付けていたのが間違いということで、実体のある構造体(末尾に }hoge; が入っている、もしくはほかのcppやhでstruct Hoge hoge のように宣言している)ではGLOBALを付けて、実体を呼んでいます。

複数のcppファイルで変数を共有するため、という単純な理由でexternを使ってはいるのですが、extern宣言だけをまとめたヘッダファイルを別途作るとなると、変数追加時の記述箇所が増えてしまうのではと思い、追加時記述が一か所で済むあの方法を使っていた次第です。

GLOBALでプリプロセス時に分ける方法はあまり好まれないのでしょうか・・・?

Re: 龍神録プログラミングの館の.h記述手法で構造体を使った場合のwarning C4091について

Posted: 2014年1月16日(木) 15:37
by usao
オフトピック
>あまり好まれないのでしょうか・・・?
好む好まないが言われるほど,そんなことが広く行われているかどうか 私は存じませんけど,

極端な例かもしれないけど,
関数の実装をあるcppに書いたけど,その関数を別のcppから使いたい
→(1)関数定義と関数宣言が,ごっちゃになってどれがどれやらわからん!
→(2)定義と宣言で複数回書かないとだめなのが嫌.一か所に書きたい
 ↓
こう書こう!OK! みたいな雰囲気というか.

コード:

//[func.h]
int Add( int a, int b )
#ifdef IMPLEMENTATION  //実装する箇所ではIMPLEMENTATIONをdefineしてからこのヘッダをincludeする
{  return a+b;  }
#else
;
#endif
ふつーに関数の宣言を書いたヘッダを用意するのが常道であろうところを,あえてこのようにするだろうか?みたいな.

動機が(1)であれば,こんな小手先の手段でごまかそうとするよりも,まずはちゃんと理解した方がいいし,
(2)であっても,こんな変なことするくらいなら,私ならがまんするなぁ.

Re: 龍神録プログラミングの館の.h記述手法で構造体を使った場合のwarning C4091について

Posted: 2014年1月16日(木) 16:13
by usao
本題がwarningについてなので (これは解決したんですよね?)
こういうことを延々と書くべきかどうか微妙な気もするけど,
そのプリプロセッサを使う方法だと,変数の初期値を指定するためのうまい方法を別途考えないと,
結局使いにくくなったりしないのかなぁ,とか思ったので,一応書いておきます.
(方法自体を否定するのではなく,もしデメリットがあるなら知っておいた方が良いだろう,という意味で)

その方法ではヘッダに

コード:

GLOBAL int img = 0;  //初期値は0にしたい
とか書いたら,複数個所からincludeすると多重定義でエラーになるだろうから,
結局どこかで(他所がimgにアクセスするよりも前に)imgに初期値相当の値を入れておく処理が必要になるわけで,
例えば,

コード:

#include "外部変数用ヘッダ.h"
int main( ... )
{
  //仕方ないので,ここらへんで外部変数に値を入れておく ということにしたとすれば
 //初期化が必要な外部変数を増やすたびに,ここに追記が必要
  img = 0;
  ...
みたいなことになるのであれば,

コード:

int img = 0;  //普通に外部変数定義

int main( ... )
{ ...
って書くのに比べて手間が減っているように見えないというか.

あと,
>複数のcppファイルで変数を共有する
方法は,外部変数をextern宣言 だけじゃないので,別の方法も検討されるとよいかも.

Re: 龍神録プログラミングの館の.h記述手法で構造体を使った場合のwarning C4091について

Posted: 2014年1月16日(木) 19:01
by ISLe
プリプロセッサで切り替える方法は、宣言と定義が曖昧になるので、開発環境のソースコード解析に悪影響を与えて、宣言や定義へのジャンプとか入力候補の表示とかがしばしば機能しなくなる現象に遭遇したりします。
データベースが更新一斉に更新される頻度も高くなりますし、開発効率が下がります。
ぱんにゃあ さんが書きました:GLOBALでプリプロセス時に分ける方法はあまり好まれないのでしょうか・・・?
そもそもexternが必要になること自体にたくさんの問題があるので、好む好まない以前の話ですね。

グローバル変数をまとめるという発想自体が構造化の否定になります。
とりあえずグローバル変数を使うとしても、プレイヤーの変数の実体はプレイヤーの処理を書くソースコードと同じにまとめるとかするべきかと。
そうじゃないとあとあと苦労しますよ。
実際に苦労してるひとをたくさん知っていますから。

Re: 龍神録プログラミングの館の.h記述手法で構造体を使った場合のwarning C4091について

Posted: 2014年1月16日(木) 20:36
by softya(ソフト屋)
Dixqさんによると龍神録の手法は分かりやすさ優先と龍神録の限定された状況での利用を推奨されています。
つまり、龍神録の構造をそのまま真似て新しいプログラムを作るのは止めたほうが良いと言うことですね。
超初心者で、龍神録を改造する時限定と考えていただいたほうが良いと思います。
もしSTGを作るなら、龍神録の構造を真似せず自分なりに書き起こせればステップアップまちがい無しです。

【補足】
新ゲームプログラミングの館では龍神録とは違うデータの持ちかたやプログラムの構造推奨で書かれているので、そちらを参考にされたほうが良いと思います。
http://dixq.net/g/
ゲームプログラミング設計 
d.1 メイン関数の作り方
d.2 複数のファイルにわけてコンパイルする
d.3 ゲームの設計と分割コンパイル(1)
d.4 ゲームの設計と分割コンパイル(2)
d.5 ゲームの設計と分割コンパイル(3)
d.6 管理部の作り方 (似た要素のまとめ方)