ファイル分割時のヘッダ部分について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
きらりん

ファイル分割時のヘッダ部分について

#1

投稿記事 by きらりん » 16年前

はじめまして。
早速なんですが質問させてください;

ヘッダ部分のグローバル関数を GV.h なんかに分割してみたんですが

1>main.obj : error LNK2001: 外部シンボル ""int random" (?random@@3HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int nrandom" (?nrandom@@3HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int a" (?a@@3HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int b" (?b@@3HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int * piece" (?piece@@3PAHA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int * npiece" (?npiece@@3PAHA)" は未解決です。

みたいなエラーが出ます。
一応ぐぐって同じグローバル変数を二度定義してしまうのがいけないことで、
それをexternで回避できることがわかった後だったりします。
それでRyuJinのコード見ながら真似事で

#ifdef _GLOBAL_INSTANCE_
#define GLOBAL
#else
#define GLOBAL extern
#endif

を上に書いて

     GLOBAL int a,b;
GLOBAL int piece[BLK_NUMBER * BLK_NUMBE[/url]; //現在のブロックタイプを記憶
GLOBAL int random; //現在のブロックタイプ
GLOBAL int npiece[BLK_NUMBER * BLK_NUMBE[/url]; //次のブロックタイプを記憶
GLOBAL int nrandom;
てな感じです。
ちなみに

GLOBAL int hitkeyframe = 0; //左右下に動かすための制御フレーム
GLOBAL int hitturnframe =0; //回転させるための制御フレーム
GLOBAL int count =0;
なんかではエラーが出ません。初期化してるのが違いなのかなーっとか思って
int a=0とかにしてみても変わりなかったです。

長くなってしまってすいません;
わかる人いたら教えて下さいm(_ _)m
コード出した方がいい場合はコードも出します。(プログラム初心者なんですごい汚いですが;)

Dixq (管理人)

Re:ファイル分割時のヘッダ部分について

#2

投稿記事 by Dixq (管理人) » 16年前

=0

にしているので、エラーになります。
この書き方では宣言と同時に格納は出来ません。

GLOBAL が空白に置き換わっているときだけ、格納し、externの時は空白になるようにしないといけません。
・・しかし、宣言と同時に格納というのはあまりしない方がいいです。
初期化する時は、初期化関数を用意するなどして格納してあげて下さい。
そうしないと、ゲームのリセットボタンなどを押した時、
変数を全て初期化するということが難しくなるからです。

なお、グローバル変数は宣言すると同時に0が入るので、0を入れる必要はありません。

Dixq (管理人)

Re:ファイル分割時のヘッダ部分について

#3

投稿記事 by Dixq (管理人) » 16年前

やろうと思えばこんな風に出来ます。
(例)

#ifdef GLOBAL_INSTANCE

#define GLOBAL
#define GLOBAL_VAL(v)	 =(v)
#define GLOBAL_ARR2(a,b) ={a,b}

#else

#define GLOBAL extern 
#define GLOBAL_VAL(v)	 
#define GLOBAL_ARR2(a,b)	 

#endif

GLOBAL int black    GLOBAL_VAL(1);//1を格納
GLOBAL int color[2] GLOBAL_ARR2(2,3);//[0]に2,[1]に3を格納
 
こうすればGLOBALが空白の時、括弧内の値を格納し、externの時空白に出来ます。

YuO

Re:ファイル分割時のヘッダ部分について

#4

投稿記事 by YuO » 16年前

CとC++を混ぜたりしていませんか?

そうであれば,
・CとC++を混ぜない
これが一番簡単な解決方法です。
つまり,全ての.cを.cppに置き換えてください。
# もちろん,C/C++の非互換によるエラーは起きるかもしれませんが。

C/C++
両方から使えることが前提なら (そもそもそういう時に外に出す大域変数があるかはともかく),
__cplusplusでextern "C"の使用の有無を切り分けることになります。

SCI

Re:ファイル分割時のヘッダ部分について

#5

投稿記事 by SCI » 16年前

そもそもDirectXを使用するプログラムで.cを使うのはよっぽどの理由がない限り避けるべきです。

BEMANI

Re:ファイル分割時のヘッダ部分について

#6

投稿記事 by BEMANI » 16年前

後、GV.h 内で 「GLOBAL int 変数名 = 初期値;」は宜しくないです。
CV.h 内では変数の宣言だけをしてあげて、
どこかに関数を作ってその中で初期化した方が宜しいかと思います。


自分もサンプルを載せておきます。


[GV.h]

// ヘッダを二回読まないようにしています(インクルードガード)
#ifndef _GLOBALSET_

#ifndef GLOBAL
#define EXTRN extern
#else
#define EXTRN
#endif

// 変数を書く所
GLOBAL int random;  // 現在のブロックタイプ
GLOBAL int nrandom;
 ・
 ・
 ・

// ここまでがインクルードガード
#else
#define _GLOBALSET_
#endif



[main.c か main.cpp]

#define GLOBAL
#include "GV.h"

void main(void)
{
 ~~~
}

SCI

Re:ファイル分割時のヘッダ部分について

#7

投稿記事 by SCI » 16年前

BEMANIさん
それはコンパイル確認・動作確認をしたのですか?
私には、とてもコンパイルが通りそうに無いように思えるのですが

SCI

Re:ファイル分割時のヘッダ部分について

#8

投稿記事 by SCI » 16年前

具体的に「なぜか」を言わなければなりませんね、すみません・・・
#ifndef _GLOBALSET_ 
    :
    :
#else 
#define _GLOBALSET_ 
#endif
インクルードガードになっていますか?C言語っぽく書くと
(もちろんはじめは x == FALSE という前提ですね)
if (!x)
{
    // 処理
}
else
{
    x = TRUE;
}
これではxがTRUEになりえませんね。

また、
GLOBAL int ... ;
のGLOBALはEXTRNの誤記でしょう。

さらに、「main.c か main.cpp」は「main.cpp」でしょう。
なぜそうなるかは分かりますよね。

Dixq (管理人)

Re:ファイル分割時のヘッダ部分について

#9

投稿記事 by Dixq (管理人) » 16年前

あと、私も以前やってたことなんですが、
アンダーバーを最初につけると予約語になるので、使ってはいけないようです。
私の昔のサンプル・・またはそれをコピペしたものにはアンダーバーが最初に付いている物があります。ごめんなさいm(_ _;)m

きらりん

Re:ファイル分割時のヘッダ部分について

#10

投稿記事 by きらりん » 16年前

@@
今教えてもらったことを読みながら作業中です。
今返事できる範囲で .c は使っていません。

あと初期化をmain内に書き換えてみたんですけどやっぱり
1>main.obj : error LNK2001: 外部シンボル ""int count" (?count@@3HA)" は未解決です。
てな感じのエラーが出ます。今までグローバル内で初期化していたやつをすべて初期化しなくしたのですべてこれがでるようになりました。

きっとexternの範囲ですよね。がんばります;w;

後でちゃんと返事書きますー><
頑張ってきます

BEMANI

Re:ファイル分割時のヘッダ部分について

#11

投稿記事 by BEMANI » 16年前

>>SCIさん
>GLOBAL int ... ;
>のGLOBALはEXTRNの誤記でしょう。

確かに、GLOBAL は EXTRNです。すいませんでした・・・。
一応ファイルを添付してみました。

BEMANI

Re:ファイル分割時のヘッダ部分について

#12

投稿記事 by BEMANI » 16年前

ファイル添付ミスです・・・すいません。

たかぎ

Re:ファイル分割時のヘッダ部分について

#13

投稿記事 by たかぎ » 16年前

そもそもGLOBALマクロの類は使うべきではありません。

グローバル変数を使うには細心の注意を払う必要があります。
にもかかわらず、グローバル変数を安易に使うのに便利なマクロを用意するのは根本的におかしいのです。

SCI

Re:ファイル分割時のヘッダ部分について

#14

投稿記事 by SCI » 16年前

BEMANIさん
まぁ、そこだけではないのですが(笑)
添付ファイル見ましたが、根本的な勘違いがあるようなので補足しておきます。

まずインクルードガードについて。
#ifndef マクロ
#define マクロ
    :
    :
#endif
が定石でしょうね。先の例ですと、_GLOBALSET_は自分でdefineしない限り永久に定義されません。

実際に
#include "Global.h"
#include "Global.h"
としてみてください。

あとはたかぎさんの言うとおりで、グローバル変数を多用する場合は注意が必要です。
便利マクロを活用するのも(一貫していれば)いいですが、まずはグローバル変数を減らすことに努めるべきでしょう。

たかぎ

Re:ファイル分割時のヘッダ部分について

#15

投稿記事 by たかぎ » 16年前

もう少し補足すると、C++でグローバル変数(より厳密には非局所オブジェクト)を使うと、初期化のタイミングの問題も絡んでくるので、非常に扱いが難しくなります。
コンストラクタからの例外に対しても、まったくの無防備になります。

お勧めの方法は、グローバル変数的に使いたいものをクラスにまとめて、関数経由でアクセスする方法です。
具体的には、
struct global_type
{
  int a;
  double b;
  ...
};

global_type& global()
{
  static global_type g;
  return g;
}
これでかなりの問題が解消されます。
あるいは、
boost::any& global(const std::string& name)
{
  static std::map<std::string, boost::any> m;
  return m[name];
}
でも、まるっきりのグローバル変数よりはずっとましです。

BEMANI

Re:ファイル分割時のヘッダ部分について

#16

投稿記事 by BEMANI » 16年前

>>SCIさん
>>#include "Global.h"
>>#include "Global.h"
・・・とやってみました。
外部シンボル ""int ABC" (?ABC@@3HA)" は未解決です。 と表示されました。

SCI

Re:ファイル分割時のヘッダ部分について

#17

投稿記事 by SCI » 16年前

BEMANIさん
それはなぜだか分かりますか?

マクロによって二重インクルード防止ができていればそのエラーは出ないはずです。

きらりん

Re:ファイル分割時のヘッダ部分について

#18

投稿記事 by きらりん » 16年前

皆さん、こんな短時間で多くのレス有難うございます><
なのですが解決できませんでしたorz
未解決という文字がトラウマになりそうです(((
今日はもう寝てまた明日頑張ります。一応GV.hだけ貼ってみるので、もしよかったら見てください。

グローバル変数を使用していること自体が問題なのか・・・、マクロが間違っているのか・・・orz

一応僕のスペックは今年大学に入って、後期から今までCを習った程度の知識しかないです;
すみません。。。一応ゲームプログラマー志望で個人的にゲーム作成を頑張っています。



>>Dixq (管理人) 様
こんな書き方もあるんですね!勉強になりました。

>>SCI 様
.cファイルは使ってないです。ですが、Cの知識しか持ってないのでclassとかは使ってないです。

>>BEMANI 様
ファイルまで容易してくれて本当に有難うございます><
マクロについてちょっとわかった気がします。

>>たかぎ 様
そうですよね;
しかし自分の実力ではなかなかグローバル変数を減らすのが大変だったので、これでも減らした方だったりますorz
まだC++についてほぼ無知なんですが、これを機会に勉強してみるのもいいかもしれませんね!
しかし、その前にやり始めたこのマクロで一回コンパイルを通したいですorz

SCI

Re:ファイル分割時のヘッダ部分について

#19

投稿記事 by SCI » 16年前

GV.hだけを見ると特に問題はなさそうですが・・・
もちろん、GV.hはプロジェクトのすべてのファイルから見えて(includeされて)いるんですよね?
だとしたら普通にアクセスできるはずですが・・・
インクルードガードをしていないみたいなので、「変数~~が未解決です」のほかに
「エラー:複数の宣言が見つかった」「エラー:重複宣言」「エラー:一つ前の定義位置」
とか、こんな感じのがあったら、多重インクルードの疑いアリです。
ファイル数が増えてくると思わず二回インクルードしてたってのはありそうですし。

あ、
>classとかは使ってないです。
DxLib(と、当然その向こうのDX8も)が内部でC++の構文をとっているので、
DxLib.hをインクルードしたソースファイルをCでコンパイルするとエラーが大量に出ると思います。
って意味です。今回は問題ないみたいなのでスルーで大丈夫です。

BEMANI

Re:ファイル分割時のヘッダ部分について

#20

投稿記事 by BEMANI » 16年前

>>SCIさん
御丁寧にありがとうございます。
今まで使い回してきたものなので、何とも思ってなかったですが、
SCIさんの仰る通り、確かに自分で定義しなければ else 側に通らず、
また、インクルードガードできていませんでした・・・。

実際そのように見えていただけだった・・・ようです。
間違ってるのに気付かずそのまま行ってしまいそうでした。
SCIさん有難う御座います。

Dixq (管理人)

Re:ファイル分割時のヘッダ部分について

#21

投稿記事 by Dixq (管理人) » 16年前

もしどうしてもおかしい所が発見出来なければ、
私の方に送っていただければこちらで確認しますよ。
→ dixqhp@gmail.com

プロジェクトに関連するファイルは~.vcprojと~.slnだけで結構です。
もし必要最低限のファイルがよくわからない時は、~.ncbファイルと「Debug」もしくは「Release」フォルダを消して、プロジェクトのあるフォルダをごっそりzipか何かに圧縮して送って下さい。

きらりん

Re:ファイル分割時のヘッダ部分について

#22

投稿記事 by きらりん » 16年前

>>SCI 様
>>>インクルードガードをしていないみたいなので

やってみたんですが、コンパイル通らなかったんで余計なことは後にしようと思いまして・・・

>>>もちろん、GV.hはプロジェクトのすべてのファイルから見えて(includeされて)いるんですよね?

一応今のところmainファイルしか作っていません。以前分割しようとしたときに多重定義で詰まったんで先にグローバル変数をどうにかしようっということで今に至ります。
なので今はmainファイルから

#include "GV.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){

....
てな感じなのがあるだけです。(もちろん後々ファイル分割するつもりです。)
ちなみにエラーを全部書くと


1>リンクしています...
1>main.obj : error LNK2001: 外部シンボル ""int random" (?random@@3HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int nrandom" (?nrandom@@3HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int count" (?count@@3HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int hitkeyframe" (?hitkeyframe@@3HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int a" (?a@@3HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int (* ColorDef)[3]" (?ColorDef@@3PAY02HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int (* fColor)[18]" (?fColor@@3PAY0BC@HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int (* field)[18]" (?field@@3PAY0BC@HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int b" (?b@@3HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int hitturnframe" (?hitturnframe@@3HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""struct tagPOINT location" (?location@@3UtagPOINT@@A)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int * piece" (?piece@@3PAHA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int (* BlkDef)[9]" (?BlkDef@@3PAY08HA)" は未解決です。
1>main.obj : error LNK2001: 外部シンボル ""int * npiece" (?npiece@@3PAHA)" は未解決です。
1>C:\Documents and Settings\natume\デスクトップ\サンプルプログラム実行用フォルダ\Release\DxLib_VC2005用.exe : fatal error LNK1120: 外部参照 14 が未解決です。

てな感じです。プロジェクト全体をアップしたほうがわかりやすそうならアップしますが、汚すぎて読めないかもですorz

きらりん

Re:ファイル分割時のヘッダ部分について

#23

投稿記事 by きらりん » 16年前

>>Dixq (管理人)
是非お願いしたいです!かなりお手上げ状態なんで・・・orz
ファイル用意して送ります。

Dixq (管理人)

Re:ファイル分割時のヘッダ部分について

#24

投稿記事 by Dixq (管理人) » 16年前

原因は

#define GLOBAL_INSTANCE

を書いてから

#include "GV.h"

をしているソースファイルがどこにも無かったという事でした。
最初はわからないことも多いと思うので、また何か解らなかったら遠慮なく聞いて下さい^^

きらりん

Re:ファイル分割時のヘッダ部分について

#25

投稿記事 by きらりん » 16年前

>> Dixq (管理人) 様
メールの方で丁寧に説明して頂き有難うございました!
ほんとにしょうもないミスですみません・・・。知らなかったので直し様がなかったのですが;

>>>最初はわからないことも多いと思うので、また何か解らなかったら遠慮なく聞いて下さい^^

本当に有難うございます><
一人でやってるとわからないことがでてくると何日間も止まっちゃうので助かります;


>>レスしてくれた皆様
夜遅くまで付き合って頂いて本当に有難うございました!
今回はミス以外にもマクロについて色々と学べてよかったと思います><
またこれを機会にグローバル部分だけでもクラスを使って見たいと思います。
本当に感謝しています。お礼できないのが心苦しいです;
有難うございました!

閉鎖

“C言語何でも質問掲示板” へ戻る