構造体もグローバル変数にしたい

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

構造体もグローバル変数にしたい

#1

投稿記事 by qppq » 14年前

構造体もグローバル変数にしたいのですが、どうすればいいでしょうか?

C言語のVC2008です。

コード:


//ソース1
#include "DxLib.h"
#include "CharaData.h"

//構造体
 Chara Chara;//このファイルの中の関数でも使えるように関数の外に書きました

ロード関数
void Load_Graph(){

ここに処理

}

//ソース2
#include<stdio.h>
#include<stdlib.h>
#include "DxLib.h"
#include "CharaData.h"

//構造体
 Chara Chara; //このファイルの中の関数でも使えるように外に書きました

//キャラ移動
void CharaMove(){

ココに処理

}

エラー内容:"struct Chara Chara" (?Chara@@3U0@A) は既に CharaMove.obj で定義されています。
        1 つ以上の複数回定義されているシンボルが見つかりました。

おそらく chara chara;が関数の外に書いてあるからだと思い、関数の中に書いたところ正常に実行できました。
でも、関数の中に書くと別の関数からはアクセスできないですよね?
如何すれば解決するでしょうか
初歩な質問だとは思いますが、よろしくおねがいします・・。

アバター
五反田
記事: 21
登録日時: 14年前
住所: 千葉

Re: 構造体もグローバル変数にしたい

#2

投稿記事 by 五反田 » 14年前

構造体の名前と変数の名前を同じものにしているせいでエラーになっているのではないでしょうか?

初級者
記事: 200
登録日時: 14年前

Re: 構造体もグローバル変数にしたい

#3

投稿記事 by 初級者 » 14年前

どれか1箇所だけで実体を定義してください。
他の箇所では extern を付けてください。

なお、構造体の型名と変数名が同じでも、一向にかまいません。

box
記事: 2002
登録日時: 14年前

Re: 構造体もグローバル変数にしたい

#4

投稿記事 by box » 14年前

ふつうは引数で受け渡しするものだと思います。
グローバル変数を使うことは、そのプログラムにおいて必須の要件ですか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

qppq

Re: 構造体もグローバル変数にしたい

#5

投稿記事 by qppq » 14年前

返信が遅れてしまい申し訳ございません。時間が取れなくて返信が遅くなってしまいました。

>どれか1箇所だけで実体を定義してください。
>他の箇所では extern を付けてください。

今作成しているプログラムを実体定義をしたまま貼り付けます。

コード:


//CharaData.h
//インクルードガード
#ifndef CHARADATA_H
#define CHARADATA_H

//TRUE FALSE判定
#define TRUE	1
#define FALSE	0

//自機定数
#define PLAYER_SPEED 1	//自機のスピード


struct Chara{
	int flag;			//自機の存在フラグ
	int hp;				//自機のHP
	int power;			//自機の攻撃力
	int RightLeft_flag;	//左右キー入力
	int UpDown_flag;	//上下キー入力
	double x;			//自機の位置X
	double y;			//自機の位置Y
	double vx;			//自機の移動量X
	double vy;			//自機の移動量Y
};

//自機データ
extern Chara Chara; //■■■■
extern int R_jikiimage;	//主人公Aの画像
extern int L_jikiimage;	//主人公Bの画像

extern void Load_Graph();
extern void CharaMove();
extern void teigi();
#endif 


//jittai.cpp
#include "CharaData.h"

Chara Chara;
void teigi(){

	Chara.flag=0;			//自機の存在フラグ
	Chara.hp=0;				//自機のHP
	Chara.power=0;			//自機の攻撃力
	Chara.RightLeft_flag=0;	//左右キー入力
	Chara.UpDown_flag=0;	//上下キー入力
	Chara.x=30;			//自機の位置X
	Chara.y=30;			//自機の位置Y
	Chara.vx=0;			//自機の移動量X
	Chara.vy=0;			//自機の移動量Y
}


//ImageDivision.cpp
#include "DxLib.h"
#include "CharaData.h"

//画像の読み込み
void Load_Graph(){
int R_jikiimage = LoadGraph( "media/jiki_a.png" );	//主人公Aの画像読み込み
int L_jikiimage = LoadGraph( "media/jiki_b.png" );	//主人公Bの画像読み込み 

}

//CharaMove.cpp
#include<stdio.h>
#include<stdlib.h>
#include "math.h"
#include "DxLib.h"
#include "CharaData.h"

//自機データ
int R_jikiimage;
int L_jikiimage;

//キャラ移動
void CharaMove(){

//キャラクター構造体定義
	
	//初期化
	Chara.RightLeft_flag = FALSE;
	Chara.UpDown_flag	 = FALSE;
            Chara Chara ;  //■■■■■
    
	int naname = 0;	//斜め移動変数

	if( CheckHitKey(KEY_INPUT_RIGHT) == TRUE ){//右キー
		Chara.RightLeft_flag = TRUE;
		Chara.vx += PLAYER_SPEED;			//右移動
	}

	if( CheckHitKey(KEY_INPUT_LEFT)   == TRUE ){//左キー
		Chara.RightLeft_flag	= TRUE;	
		Chara.vx -= PLAYER_SPEED;			//左移動
	}

	if( CheckHitKey(KEY_INPUT_UP)    == TRUE ){//上キー
		Chara.UpDown_flag	= TRUE;	
		Chara.vy += PLAYER_SPEED;			//上移動
	}

	if( CheckHitKey(KEY_INPUT_DOWN)  == TRUE ){//下キー
		Chara.UpDown_flag    = TRUE;	
		Chara.vy -= PLAYER_SPEED;			//下移動
	}

	//斜め処理(斜めでも速度を一定に)
	if( Chara.RightLeft_flag == TRUE && Chara.UpDown_flag == TRUE ){
		naname =sqrt(2.0);	//1/√2
		(Chara.vx / naname);
		(Chara.vy / naname);
	}

	Chara.x += Chara.vx;
	Chara.y += Chara.vy;
	DrawGraph( Chara.x, Chara.y, R_jikiimage, TRUE );
	DrawFormatString(0,0,GetColor(255,255,255),"%d",Chara.x);
	}


//Main.cpp
#include<stdio.h>
#include<stdlib.h>
#include "DxLib.h"
#include "CharaData.h"

int Key[256];
int Color = GetColor( 255, 255, 255 ); //基本(黒) 
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
	char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
        else                            GetHitKeyStateAll_InputKey[i]=0;
    }
    return 0;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
	// 画面モードの設定
	teigi();//■■■■
	Load_Graph();	//画像のロード

	if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
 
	while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
		//↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない

	CharaMove();	//自機移動
		


	ScreenFlip();
 }   
 
    DxLib_End();
    return 0;
}

長くなるのでソースは書かなかったのですが、やっぱり書くことにしました。
他の箇所ではexternする。とのことですが、 
CharaMove.cpp にある Chara Chara;を extern Chara Chara; にするということですか?


>グローバル変数を使うことは、そのプログラムにおいて必須の要件ですか?
たしかにグローバル変数はなるべく使いたくないのですが、キャラクターの座標や攻撃力などを管理しているので、仕方なく使っています。
グローバル変数を使わずに出来る方法があるなら、ぜひ教えてください!

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

Re: 構造体もグローバル変数にしたい

#6

投稿記事 by h2so5 » 14年前

qppq さんが書きました: たしかにグローバル変数はなるべく使いたくないのですが、キャラクターの座標や攻撃力などを管理しているので、仕方なく使っています。
グローバル変数を使わずに出来る方法があるなら、ぜひ教えてください!
WinMain内でローカル変数として宣言して、引数でポインタを渡せば可能です。

box
記事: 2002
登録日時: 14年前

Re: 構造体もグローバル変数にしたい

#7

投稿記事 by box » 14年前

qppq さんが書きました:

コード:

	//初期化
	Chara.RightLeft_flag = FALSE;
	Chara.UpDown_flag	 = FALSE;
            Chara Chara ;  //■■■■■
Chara にアクセスした後で定義するのって、論理的におかしくないですか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

qppq

Re: 構造体もグローバル変数にしたい

#8

投稿記事 by qppq » 14年前

ご回答ありがとうございます。

>Chara にアクセスした後で定義するのって、論理的におかしくないですか?

あ!全然気づきませんでした・・。

コード:

//自機データ
int R_jikiimage;
int L_jikiimage;
Chara Chara; //このファイルでChara構造体を使いたいので。

//キャラ移動
void CharaMove(){

//キャラクター構造体定義
	
	//初期化
	
	Chara.RightLeft_flag = FALSE;
	Chara.UpDown_flag	 = FALSE;

訂正して、デバッグしてみました。
それでもエラーが出ます。
構文エラー : ';' が、識別子 'Chara' の前に必要です
型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
'Chara' : 再定義されています。異なる基本型です。
'Chara' の宣言を確認してください。
';' が、識別子 'Chara' の前に必要です。

このエラーが数個出ます。


>WinMain内でローカル変数として宣言して、引数でポインタを渡せば可能です。

なるほど・・メイン関数の中でローカル変数で宣言するとは考えもしませんでした。
しかし、引数でポインタを渡す・・・・ポインタは難しいのでなるべく避けたいですね・・。
難しくて、必死で勉強したのですが、使いどころが文字列くらいしか思いつかず、全然ポインタを使ってなかったので勉強した内容を忘れてしまって・・。
こういう場面でポインタを使うのですね。また今度ポインタの勉強してやってみたいと思います。

アバター
やっくん
記事: 5
登録日時: 14年前
住所: 長崎県長崎市

Re: 構造体もグローバル変数にしたい

#9

投稿記事 by やっくん » 14年前

こんばんは、初めまして。

>構文エラー : ';' が、識別子 'Chara' の前に必要です
Chara Chara;をstruct Chara Chara;と治せばいけるかと思います。

その後も少々リンクエラーが出ました。
jittai.cppとCharaMove.cppで2度Chara Charaと実体を作っているのに対してのエラーです。

>難しくて、必死で勉強したのですが、使いどころが文字列くらいしか思いつかず,
例えば、構造体をポインタで引数に渡す利点として先頭アドレスを渡すのみですので構造体の値を一つ一つコピーしなくて済むということがあげられます。大量のデータを引数で受け渡す場合には処理速度が大きく変わってきます。
他にも変数の要素の大きさを動的(プログラム実行中)に決定できたりとするので便利です。

qppq

Re: 構造体もグローバル変数にしたい

#10

投稿記事 by qppq » 14年前

ご回答ありがとうございます。

試してみたところ実行できました。
しかし、変数の中身が初期化?されてしまうのですが・・。

初期化されてしまう変数

extern Chara Chara;
extern int R_jikiimage; //主人公Aの画像
extern int L_jikiimage; //主人公Bの画像

extern struct Chara Chara;
は、主人公のデータを保存する構造体です。

extern int R_jikiimage; は主人公の画像Aの保存する変数です。
extern int L_jikiimage;は主人公の画像Bの保存する変数です。

実行すると、主人公の画像が表示されず、DrawFormatString()関数で構造体のx座標を見てみたところ、0のままでした。
何度も何度もすみません・・・。

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

Re: 構造体もグローバル変数にしたい

#11

投稿記事 by h2so5 » 14年前

ソースを全部載せてください。

コード:

DrawFormatString(0,0,GetColor(255,255,255),"%d",Chara.x);
それと、このままだと指定子が間違っていますね。

pqpq

Re: 構造体もグローバル変数にしたい

#12

投稿記事 by pqpq » 14年前

あ、doubleだから指定子は、%fでしたね。
構造体のほうはできたのですが、主人公の画像が表示されません。場所は間違ってないと思うのですが・・・。

とりあえずコード張っておきます。

コード:

//CharaData.h
//インクルードガード
#ifndef CHARADATA_H
#define CHARADATA_H

//TRUE FALSE判定
#define TRUE	1
#define FALSE	0

//自機定数
#define PLAYER_SPEED 1	//自機のスピード


struct Chara{
	int flag;			//自機の存在フラグ
	int hp;				//自機のHP
	int power;			//自機の攻撃力
	int RightLeft_flag;	//左右キー入力
	int UpDown_flag;	//上下キー入力
	double x;			//自機の位置X
	double y;			//自機の位置Y
	double vx;			//自機の移動量X
	double vy;			//自機の移動量Y
};

//自機データ
extern struct Chara Chara;
extern int R_jikiimage;	//主人公Aの画像
extern int L_jikiimage;	//主人公Bの画像

extern void Load_Graph();
extern void CharaMove();
extern void teigi();
#endif 

コード:

//ImageDivision.cpp
#include "DxLib.h"
#include "CharaData.h"

//画像の読み込み
void Load_Graph(){
int R_jikiimage = LoadGraph( "media/jiki_a.png" );	//主人公Aの画像読み込み
int L_jikiimage = LoadGraph( "media/jiki_b.png" );	//主人公Bの画像読み込み 

}

コード:

//jittaiteigi.cpp
#include "CharaData.h"

struct Chara Chara;
void teigi(){

	Chara.flag=0;			//自機の存在フラグ
	Chara.hp=0;				//自機のHP
	Chara.power=0;			//自機の攻撃力
	Chara.RightLeft_flag=0;	//左右キー入力
	Chara.UpDown_flag=0;	//上下キー入力
	Chara.x=30;			//自機の位置X
	Chara.y=30;			//自機の位置Y
	Chara.vx=0;			//自機の移動量X
	Chara.vy=0;			//自機の移動量Y
	//自機データ

}

コード:

//CharaMove.cpp
#include<stdio.h>
#include<stdlib.h>
#include "math.h"
#include "DxLib.h"
#include "CharaData.h"

int R_jikiimage;
int L_jikiimage;

//キャラ移動
void CharaMove(){

//キャラクター構造体定義
	
	//初期化
	
	Chara.RightLeft_flag = FALSE;
	Chara.UpDown_flag	 = FALSE;


	int naname = 0;	//斜め移動変数

	if( CheckHitKey(KEY_INPUT_RIGHT) == TRUE ){//右キー
		Chara.RightLeft_flag = TRUE;
		Chara.vx += PLAYER_SPEED;			//右移動g
	}

	if( CheckHitKey(KEY_INPUT_LEFT)   == TRUE ){//左キー
		Chara.RightLeft_flag	= TRUE;	
		Chara.vx -= PLAYER_SPEED;			//左移動
	}

	if( CheckHitKey(KEY_INPUT_UP)    == TRUE ){//上キー
		Chara.UpDown_flag	= TRUE;	
		Chara.vy += PLAYER_SPEED;			//上移動
	}

	if( CheckHitKey(KEY_INPUT_DOWN)  == TRUE ){//下キー
		Chara.UpDown_flag    = TRUE;	
		Chara.vy -= PLAYER_SPEED;			//下移動
	}

	//斜め処理(斜めでも速度を一定に)
	if( Chara.RightLeft_flag == TRUE && Chara.UpDown_flag == TRUE ){
		naname =sqrt(2.0);	//1/√2
		(Chara.vx / naname);
		(Chara.vy / naname);
	}

	Chara.x += Chara.vx;
	Chara.y += Chara.vy;
	Chara.vx=0;
	Chara.vy=0;

	DrawGraph( Chara.x, Chara.y, R_jikiimage, TRUE );
	DrawFormatString(0,0,GetColor(255,255,255),"%f",Chara.x);

	}

コード:

//Main.cpp
#include<stdio.h>
#include<stdlib.h>
#include "DxLib.h"
#include "CharaData.h"

int Key[256];
int Color = GetColor( 255, 255, 255 ); //基本(黒) 
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
	char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
        else                            GetHitKeyStateAll_InputKey[i]=0;
    }
    return 0;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
	// 画面モードの設定
	teigi();
	Load_Graph();	//画像のロード

	if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
 
	while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
		//↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない

	CharaMove();	//自機移動
		


	ScreenFlip();
 }   
 
    DxLib_End();
    return 0;
}

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

Re: 構造体もグローバル変数にしたい

#13

投稿記事 by h2so5 » 14年前

pqpq さんが書きました:あ、doubleだから指定子は、%fでしたね。
doubleの指定子は %lf です。
pqpq さんが書きました: 構造体のほうはできたのですが、主人公の画像が表示されません。場所は間違ってないと思うのですが・・・。
Charaのx座標が0になる問題は解決したということでしょうか?

あと、「場所が間違っていないはずなのに画像が表示されない」という話はこの掲示板で良く聞きますが、
たいてい場所が間違っています。

画像が読み込めているかどうかは LoadGraphの戻り値を調べれば分かります。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 構造体もグローバル変数にしたい

#14

投稿記事 by ISLe » 14年前

表示するほうなので%fで良いですよ。

画像が表示されないのはDxLib_InitでDXライブラリを初期化する前にLoadGraphしてるからだと思います。

qppq

Re: 構造体もグローバル変数にしたい

#15

投稿記事 by qppq » 14年前

ご回答ありがとうございます。

初期化された後にloadgraphしてみました。

コード:

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
	// 画面モードの設定

	if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
	
	teigi();
	Load_Graph();	//画像のロード
それでも画像が表示されませんでした。
main関数の中にいれても表示されませんでした・・。

>画像が読み込めているかどうかは LoadGraphの戻り値を調べれば分かります。

どこで調べればいいのか分からなかったので、main関数と、CharaMove関数と teigi関数の中で調べてみました。
if(R_jikiimage == -1)DrawString(0,10,"画像がない!",GetColor(255,255,255));
こんな感じのをそれぞれの関数に入れて調べてみても 画像がない! と表示されません。ということは、画像が読み込まれているということですよね・・?

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 構造体もグローバル変数にしたい

#16

投稿記事 by ISLe » 14年前

よく見たらLoad_Graph関数の中で、R_jikiimage,L_jikiimageがローカルに宣言されてますね。

qppq

Re: 構造体もグローバル変数にしたい

#17

投稿記事 by qppq » 14年前

>よく見たらLoad_Graph関数の中で、R_jikiimage,L_jikiimageがローカルに宣言されてますね。

あ、確かに!

コード:

//ImageDivision.cpp
#include "DxLib.h"
#include "CharaData.h"

int R_jikiimage;
int L_jikiimage;
//画像の読み込み
void Load_Graph(){
R_jikiimage = LoadGraph( "media/jiki_a.png" );	//主人公Aの画像読み込み
L_jikiimage = LoadGraph( "media/jiki_b.png" );	//主人公Bの画像読み込み 

}
こんな感じに直しました。
すると、エラーで既に定義してある。とでたので、 CharaMove.cppのほうも訂正して

int R_jikiimage;
int L_jikiimage;
CharMove.cppのこの部分を消しました。

これで実行すると、やはり画像が表示されません。念のため、LoadGraph()の戻り値を調べてみたところ、画像はちゃんと読み込まれていました。
う~ん・・どこがいけないのでしょうか・・。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 構造体もグローバル変数にしたい

#18

投稿記事 by ISLe » 14年前

qppq さんが書きました:すると、エラーで既に定義してある。とでたので、 CharaMove.cppのほうも訂正して
int R_jikiimage;
int L_jikiimage;
CharMove.cppのこの部分を消しました。
定義を移動する必要はなかったんですけどね。
qppq さんが書きました:これで実行すると、やはり画像が表示されません。念のため、LoadGraph()の戻り値を調べてみたところ、画像はちゃんと読み込まれていました。
う~ん・・どこがいけないのでしょうか・・。
現段階で全体がどうなっているのか分からなくなってるので何とも言えないですね。
Load_Graph関数の出口をブレークポイントで止めてR_jikiimageに格納された値を確認して、次にCharaMove関数でDrawGraphしている箇所をブレークポイントで止めて、R_jikiimageやChara.x,Chara.yが異常な値になっていないか調べてみてください。

qppq

Re: 構造体もグローバル変数にしたい

#19

投稿記事 by qppq » 14年前

無事出来ました!!

でも、
DrawFormatString(30,30,Color,"%d",R_jikiimage);
で調べてみると、134414339 っていう変な数字が入っています。
でも、画像は一応表示されているので、解決したということですか・・?

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

Re: 構造体もグローバル変数にしたい

#20

投稿記事 by h2so5 » 14年前

qppq さんが書きました:無事出来ました!!

でも、
DrawFormatString(30,30,Color,"%d",R_jikiimage);
で調べてみると、134414339 っていう変な数字が入っています。
でも、画像は一応表示されているので、解決したということですか・・?
R_jikiimageが-1でないなら画像が読み込まれているということです。
R_jikiimageが格納するのは画像の識別番号なのでその結果は正常です。

qppq

Re: 構造体もグローバル変数にしたい

#21

投稿記事 by qppq » 14年前

なるほど!てっきり識別番号っていうのは1から始まるのかと思ってました。

適当な数字なんですね。
皆様ご回答・ご返信ありがとうございます。無事解決できました!
本当にありがとうございます!

閉鎖

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