外部ファイルの変数の参照

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
はるさん
記事: 8
登録日時: 11年前

外部ファイルの変数の参照

#1

投稿記事 by はるさん » 9年前

最近DXLIBを学び始めて、分割コンパイルをしてみたときに気になったことがあります。MAIN文をすっきりさせるためにこのようなコードを書きました
ねらいとしては画面(0,0)座標におはようの文字と画像が現れるようにしたかったです。
しかし、「エラー 1 error LNK2005: "char * name" (?name@@3PADA) は既に main.obj で定義されています。 E:\ダウンロード\GameProg_2012 (1)\gameprog2012(練習)\player.obj GameProg_2012
」というエラーが出ました。
これができればゲームでも敵の位置やスコアなどあらゆる情報を初期化用cpp1つにまとめることができると思ったのですが。。。
なぜこの書き方がまずいのか解答よろしくお願いします。また、初期値設定は今後どういった形でまとめたらいいのかも教えてもらえればうれしいです

main.cpp

コード:

#include "DxLib.h"
#include "Player.h" 

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){
	ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK);

	Player_Initialize(); // 初期化
	
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0){
		Player_Update();  //計算
		Player_Draw(); //描画
		DrawFormatString(0,0, GetColor(255, 255, 255),name );
	}

	Player_Finalize(); // 終了処理

	DxLib_End();
	return 0;
}
player.cpp

コード:

#include "DxLib.h"
#include "keyboard.h"
#include"player.h"

// このファイル内でしか使えないグローバル変数
static int m_Image; //画像ハンドル
static int m_y;     //y座標

// 初期化をする
void Player_Initialize(){
	char name[100] = "おはよう";
	m_Image = LoadGraph("画像/キャラクタ01.png");
	m_y = 0;
}

// 動きを計算する
void Player_Update(){
	if (Keyboard_Get(KEY_INPUT_UP)>0)
	{
		m_y--;
	}
	if (Keyboard_Get(KEY_INPUT_DOWN)>0)
	{
		m_y++;
	}
}

// 描画する
void Player_Draw(){
	DrawGraph(0, m_y, m_Image, TRUE);
}

// 終了処理をする
void Player_Finalize(){
	DeleteGraph(m_Image);
}
player.h

コード:

#ifndef DEF_PLAYER_H //二重include防止

#define DEF_PLAYER_H
char name[10];
// 初期化をする
void Player_Initialize();

// 動きを計算する
void Player_Update();

// 描画する
void Player_Draw();

// 終了処理をする
void Player_Finalize();

#endif 

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 外部ファイルの変数の参照

#2

投稿記事 by みけCAT » 9年前

はるさん さんが書きました:なぜこの書き方がまずいのか解答よろしくお願いします。
プリプロセッサによってmain.cppは

コード:

(DxLib.hの中身)

char name[10];
// 初期化をする
void Player_Initialize();

// 動きを計算する
void Player_Update();

// 描画する
void Player_Draw();

// 終了処理をする
void Player_Finalize();

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){
	ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK);

	Player_Initialize(); // 初期化
	
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0){
		Player_Update();  //計算
		Player_Draw(); //描画
		DrawFormatString(0,0, GetColor(255, 255, 255),name );
	}

	Player_Finalize(); // 終了処理

	DxLib_End();
	return 0;
}
という感じに、player.cppはkeyboard.hでDEF_PLAYER_Hが定義されていなければ

コード:

(DxLib.hの中身)
(keyboard.hの中身)
char name[10];
// 初期化をする
void Player_Initialize();

// 動きを計算する
void Player_Update();

// 描画する
void Player_Draw();

// 終了処理をする
void Player_Finalize();

// このファイル内でしか使えないグローバル変数
static int m_Image; //画像ハンドル
static int m_y;     //y座標

// 初期化をする
void Player_Initialize(){
	char name[100] = "おはよう";
	m_Image = LoadGraph("画像/キャラクタ01.png");
	m_y = 0;
}

// 動きを計算する
void Player_Update(){
	if (Keyboard_Get(KEY_INPUT_UP)>0)
	{
		m_y--;
	}
	if (Keyboard_Get(KEY_INPUT_DOWN)>0)
	{
		m_y++;
	}
}

// 描画する
void Player_Draw(){
	DrawGraph(0, m_y, m_Image, TRUE);
}

// 終了処理をする
void Player_Finalize(){
	DeleteGraph(m_Image);
}
という感じに展開されます。(実際はコメントも消されたり処理前のファイル名と行数の情報が追加されたりするはずです)

この2個の翻訳単位の両方にグローバル変数nameが定義されているので、衝突してリンクエラーになります。

また、Player_Initialize関数の

コード:

char name[100] = "おはよう";
という行も、一度も使われない無駄なデータの格納処理をしているので、警告をエラーにする設定にしていなければコンパイルエラーにはならないはずですがよくないです。
はるさん さんが書きました:また、初期値設定は今後どういった形でまとめたらいいのかも教えてもらえればうれしいです
「いい」かどうかはよくわかりませんが、
龍神録プログラミングの館 5章 宣言の仕方を工夫しよう
でやっているようにすれば、コンパイル・リンクは通ると思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

はるさん
記事: 8
登録日時: 11年前

Re: 外部ファイルの変数の参照

#3

投稿記事 by はるさん » 9年前

ありがとうございます。あのあとどう頑張っても別関数にcharを定義して初期設定したのち、別の関数から参照しようとがんばったのですができませんでした。
慣れないうちはとりあえず、動くプログラムを書いていきます

かずま

Re: 外部ファイルの変数の参照

#4

投稿記事 by かずま » 9年前

player.h には、
extern char name[10]; (または、extern char name[];) と書く。

player.c には、
グローバルに、char name[10] = "おはよう"; と書く。

なお、プログラム実行中に name の内容が変更され、
Player_Initialize() で、"おはよう" に再設定が必要なら、
Player_Initialize() の中に、strcpy(name, "おはよう"); と書く。

かずま

Re: 外部ファイルの変数の参照

#5

投稿記事 by かずま » 9年前

かずま さんが書きました:player.c には、
グローバルに、char name[10] = "おはよう"; と書く。
player.cpp でした。
かずま さんが書きました:なお、プログラム実行中に name の内容が変更され、
Player_Initialize() で、"おはよう" に再設定が必要なら、
Player_Initialize() の中に、strcpy(name, "おはよう"); と書く。
Player_Initiallize() の中に、char name[10]; を書いてはいけません。
その name は、グローバルな char name[10]; の name とは別物です。

閉鎖

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