分割コンパイルについて

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

分割コンパイルについて

#1

投稿記事 by きずなん » 14年前

2DRPG作成中です。
分割コンパイル3の説明が分からないから分割しないままmain.cに書き続けてきたんですが、
main.cがもう2000行以上あって、どこに何があるかこんがらがってきたのでもう一回分割に挑戦しました。
ですが、やはりサイトの説明の意味がよく分からないので質問します・・・。
質問が2点あります。

1.
#include A.hと書けば、A.hの中身を最初に書いたことと同じって説明がありましたよね。
なので、例えばmain.cとA.hとA.cってファイルを作ったとして、
A.h-----------------
#ifndef DEF_LOAD_H
#define DEF_LOAD_H
int Box1;
Box1 = LoadGraph(~~)
void Test_Graph();
#endif
---------------------
とか書いておいて、A.cに
A.cpp-----------------
#include "DxLib.h"
#include "A.h"
void Test_Graph(){
DrawGraph(x座標,y座標, Box1 , TRUE);
}
---------------------
としておき、最後にmain.cに
main.cpp-------------
#include "DxLib.h"
#include "A.h"
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen( DX_SCREEN_BACK );
while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 ){
Test_Graph();
};
DxLib_End();
return 0;
}
---------------------
としておくと、「:\documents and settings\kk2\my documents\visual studio 2008\projects\gameprog\player.cpp(11) : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
c:\documents and settings\kk2\my documents\visual studio 2008\projects\gameprog\player.cpp(11) : error C2086: 'int Box1' : 再定義されました。
c:\documents and settings\kk2\my documents\visual studio 2008\projects\gameprog\load.h(7) : 'Box1' の宣言を確認してください。」

と表示されます。再定義で調べてみると、二重インクルードのせいというのがよく見つかりましたが、
そう思って紹介されていたA.hに二重インクルード防止の定義を足してもこのようにエラーします。
どこがおかしいのでしょうか?



2.
上の例で、main.cの最初のwhileループを抜けるのに、A.cppにおいた関数の計算結果を使いたいです。
main.cで、
while(~~){
Aにおいてる関数
   if( Aにおいてる関数で得た値 > ~~){
   break;
   }
}
として、whileループを抜けるためにAで計算した結果を判断材料にしたいのですがよく分かりません。
試してみたのは、そのif~を関数にしたんですが、A.cppで「break;」って書いてもエラーするだけでした。
どうしたらよいでしょうか。


分かりにくくてごめんなさい。片方だけでもいいのでお願いします。

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: 分割コンパイルについて

#2

投稿記事 by h2so5 » 14年前

1.について

A.h の中に
Box1 = LoadGraph(~~)
とありますが、関数の外で変数に対する代入はできません。

2.について

意味がよくわからないので具体的なコードを書いて下さい。

YuO
記事: 947
登録日時: 15年前
住所: 東京都世田谷区

Re: 分割コンパイルについて

#3

投稿記事 by YuO » 14年前

きずなん さんが書きました:#include A.hと書けば、A.hの中身を最初に書いたことと同じって説明がありましたよね。
正確には,

コード:

#include "A.h"
かと。
きずなん さんが書きました:としておくと、「:\documents and settings\kk2\my documents\visual studio 2008\projects\gameprog\player.cpp(11) : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
c:\documents and settings\kk2\my documents\visual studio 2008\projects\gameprog\player.cpp(11) : error C2086: 'int Box1' : 再定義されました。
c:\documents and settings\kk2\my documents\visual studio 2008\projects\gameprog\load.h(7) : 'Box1' の宣言を確認してください。」
player.cppって何でしょうか。
きずなん さんが書きました:と表示されます。再定義で調べてみると、二重インクルードのせいというのがよく見つかりましたが、
そう思って紹介されていたA.hに二重インクルード防止の定義を足してもこのようにエラーします。
どこがおかしいのでしょうか?
player.cppの11行目に,Box1の定義がありませんか。
# A.hのコードを見る限り,関数に属さない式文を書いている気がしますが……。

二重インクルードというのは,

コード:

#include "A.h"
#include "A.h"
というような場合のことです。
で,インクルードガードは,二度目のインクルードをしてもエラーが起きないようにするための物です。
# 上記のコード片は極端ですが,インクルードファイル経由で多重インクルードすることは多々あります。

今回の場合,エラーメッセージを見るとplayer.cppの11行目とload.hの7行目で別々にBox1を定義しているようです。
このため,インクルードガードでは対処することが出来ません。

きずなん さんが書きました:上の例で、main.cの最初のwhileループを抜けるのに、A.cppにおいた関数の計算結果を使いたいです。
main.c (main.cpp?) にその関数がある場合に,計算結果はどのように使うか,を考えてみて下さい。
それと同じ方法になります。

なので,基本的には関数の戻り値として計算結果を返すことになるでしょう。

きずなん さんが書きました:として、whileループを抜けるためにAで計算した結果を判断材料にしたいのですがよく分かりません。
試してみたのは、そのif~を関数にしたんですが、A.cppで「break;」って書いてもエラーするだけでした。
どうしたらよいでしょうか。
「ループからの脱出」自体を関数に含めることは出来ません。

なので,例えば,

コード:

// A.cpp
extern "C" int func () {
 /* 処理 */
 return 計算結果;
}

コード:

// main.c
int func (void);

int main (void)
{
 /* 省略 */
 while (1) {
  /* 省略 */
  int func_result = func();
  if (func_result > 0) {
   break;
  }
 }
}
のようになると思います。

きずなん

Re: 分割コンパイルについて

#4

投稿記事 by きずなん » 14年前

>関数の外で変数に対する代入はできない
A.cppの上らへんに書けば代入できるんですけど、これって関数の中にある扱いなんですか?

コード:

#include "DxLib.h"
#include "Keyboard.h"
#include "Load.h"

static int x,y,muki,walking_flag,char00;
static int SelectNum;
static int IM_flag;
int f1= 10;
int a = 20;
int Cr = GetColor(255,255,255);

int Box1 = LoadGraph("画像/四角2.png");


//テスト
void Test_Graph(){
	DrawFormatString(20,20,GetColor(255,255,255),"%d",f1+a);
}
	


// 初期化
void Player_Initialize(){
	IM_flag = 0;
	x = 320;
	y = 224;
	muki = 2;
	walking_flag = 0;
	char00 = LoadGraph("画像/キャラクタ10.png");
	SelectNum = 0;
}

// 進入判定
void INorOUT(){
	if(IM_flag = 1){
		int f1 = 2;
	}
}

// 動きを計算する
void Player_Calc(){

        if(x%32==0 && y%32==0){
            walking_flag=1;
			if ( Keyboard_Get( KEY_INPUT_UP ) == 1 ){
				    muki=0;
			} else if( Keyboard_Get( KEY_INPUT_LEFT ) == 1 ){
                    muki=1;
			} else if( Keyboard_Get( KEY_INPUT_DOWN ) == 1 ){ 
				    muki=2;
			} else if( Keyboard_Get( KEY_INPUT_RIGHT ) == 1){
				    muki=3;
			} else {
				    walking_flag=0;
			}
		}
 
        if(walking_flag==1){
            if     (muki==0)
                    y--;
            else if(muki==1)
                    x--;
            else if(muki==2)
                    y++;
            else if(muki==3)
                    x++;
        }
}

// 描画する
void Player_Graph(){
        DrawGraph( x, y, char00, TRUE );
}

// 終了処理をする
void Player_Finalize(){
        DeleteGraph( char00 );
}


// メニュー表示処理
void I_Menu_Calc(){
			if ( Keyboard_Get( KEY_INPUT_DOWN ) == 1 ){
				    SelectNum = ( SelectNum + 5 )%4;
			} else if( Keyboard_Get( KEY_INPUT_UP ) == 1 ){
				    SelectNum = ( SelectNum + 3 )%4;
			}
}

void I_Menu_Graph(){

			DrawRotaGraph( 320, 240, 2, 0 , LoadGraph("画像/title01.png") , TRUE );
			SetDrawBlendMode( DX_BLENDMODE_ALPHA, 150 );
			DrawGraph( M1, M2, LoadGraph("画像/四角2.png"),TRUE);
			SetDrawBlendMode( DX_BLENDMODE_NOBLEND,  0 );
			DrawFormatString(100,100,Cr,"M1の値は%d",M1);

}



2.

例えばmain.cの本編ループ部分のコードが

コード:

       //本編ループ
        while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 ){



			//開始画面ループ
				while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 ){
				Keyboard_Update();
					Keyboard_Update();
					I_Menu_Calc();  //メニュー計算
					I_Menu_Graph(); //メニュー描画
					Test_Graph();
					DrawFormatString(200,200,GetColor(255,0,0),"脱出成功。");
                
                 ~~~~~~~~~~~~                 

			}//開始画面判定終わり
                 
                //セカンドループ
          while(~~){~~
                        }//セカンドループ終わり
        }//本編ループ終わり
として、この最初の開始画面ループからセカンドループに行きたいんですよ。
そしたら~~~~~~~の部分に、break;を入れる必要があるじゃないですか。
この~~~~~~~の部分に、
if( A.cppの関数で計算した値 > ある値){ break; }
を入れたいんです。
例えば歩数の計算をA.cppでして、歩数の合計をSUM(これもA.cppの関数で求める)とすると
if(SUM > 5){ break;} としたいわけです。
でも、SUMはmainじゃなくてA.cppのほうで求めた値だから、エラーが起きるじゃないですか。
このSUM(A.cで求めた値)をmainで使いたいということです。

きずなん

Re: 分割コンパイルについて

#5

投稿記事 by きずなん » 14年前

>YuOさん
ありがとうございます。
2の方は意味が分かりました。

きずなん

Re: 分割コンパイルについて

#6

投稿記事 by きずなん » 14年前

追記ですが、1の方試してみると原因が分かりました。

//A.h--------------
int Box1;
Box1 = LoadGraph("画像/四角2.png");
//------------------
と書いてincludeするとエラーしますが
//A.h--------------
int Box1 = LoadGraph("画像/四角2.png");
//------------------

と書くとエラーしませんでした。
上と下だと、上が「関数の外での定義」で下が「関数の中での定義」になるんでしょうか?

YuO
記事: 947
登録日時: 15年前
住所: 東京都世田谷区

Re: 分割コンパイルについて

#7

投稿記事 by YuO » 14年前

きずなん さんが書きました:>関数の外で変数に対する代入はできない
A.cppの上らへんに書けば代入できるんですけど、これって関数の中にある扱いなんですか?
代入ではなく,初期化をしていますよね。
初期化は可能です。
初期化と代入は異なります。
# 特に,C++の場合。

きずなん さんが書きました:例えば歩数の計算をA.cppでして、歩数の合計をSUM(これもA.cppの関数で求める)とすると
if(SUM > 5){ break;} としたいわけです。
でも、SUMはmainじゃなくてA.cppのほうで求めた値だから、エラーが起きるじゃないですか。
このSUM(A.cで求めた値)をmainで使いたいということです。
SUMっていうのは,グローバル変数ですか。
そうであるならば,外部宣言をしてやればmain.cからも使えます。
# まあ,C++とCの違いがあるので,C++側でextern "C"の修飾が必要になりますが。

ただ,そもそも歩数の合計を計算する関数の戻り値じゃないの,という気はしますが。

きずなん

Re: 分割コンパイルについて

#8

投稿記事 by きずなん » 14年前

>Yuoさん
>ただ,そもそも歩数の合計を計算する関数の戻り値じゃないの,という気はしますが。
確かにその通りですね。・・・というか当たり前ですね。
なんかちょっと考えれば当たり前すぎることを質問してました。
疲れてるのか考えが狂ってました。
ご返答ありがとうございました。

きずなん

Re: 分割コンパイルについて

#9

投稿記事 by きずなん » 14年前

解決でした。すいません。

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: 分割コンパイルについて

#10

投稿記事 by beatle » 14年前

解決しちゃっていますが,気になる点をいくつか.
  • ヘッダファイルの中で変数の「定義」をしている.ヘッダではextern宣言すべき.恐らくコンパイル・リンクの流れが分かっていない.
  • どうしてCとC++のファイルを混ぜて開発しているのか.
  • 本編ループの中に開始画面ループがある.これは書いてはいけない4つの処理に該当する.
  • DxLib_Init()を呼び出すまえにLoadGraph()を呼び出している(DxLibに詳しくないため,これが本当にダメなのかは分からない).

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 分割コンパイルについて

#11

投稿記事 by softya(ソフト屋) » 14年前

グローバル変数の初期化にDxLIB関係の命令は使ってはいけません。必ず問題を起こします。

ここに書かれていることは守りましょう。特に例あげたものは読んで下さい。
「新・C言語 ~ゲームプログラミングの館~ [DXライブラリ]」
http://dixq.net/g/
h.11 書いてはいけない4つの処理
d.1 メイン関数の作り方
d.2 複数のファイルにわけてコンパイルする
d.3 ゲームの設計と分割コンパイル(1)
d.4 ゲームの設計と分割コンパイル(2)
d.5 ゲームの設計と分割コンパイル(3)

タイトル画面の作り方とかは私の講座で書いてあるんですが読まれてませんか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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