ヘッダファイル

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

ヘッダファイル

#1

投稿記事 by chunezu » 17年前

シューティングの館にあるように、ヘッダファイルをつかって構造体を呼び出すと言う事をしようとしています。

/* kouzou.h */

typedef struct{
double x,y,size;
int flag;
double angle;
}Player;

Player nz;


typedef struct{
int flag,pattern;
int x,y,size;
}Tama;

Tama t;


/*extern.h*/

typedef struct{
double x,y,size;
int flag;
double angle;
}Player;

extern Player nz;


typedef struct{
int flag,pattern;
int x,y,size;
}Tama;

extern Tama t;

コンパイルすると、

'Player' : 再定義されています。異なる基本型です。
'Tama' : 再定義されています。異なる基本型です。

とエラーが出てきてしまいます。
ググッてみてもさっぱり原因が分かりません。
一体どうしたらいいでしょうか?

OSはXPで、コンパイラがVisual C++2005です。

box

Re:ヘッダファイル

#2

投稿記事 by box » 17年前

> コンパイルすると、

当該のヘッダーファイル群をインクルードしている
ソースファイルの中身はどうなっていますか?

ヘッダーファイルだけ見ても、「同じ構造体を
複数のヘッダーファイルで定義していると、
保守しづらくて仕様変更に弱いだろうなあ」ということがわかるだけです。

tk-xleader

Re:ヘッダファイル

#3

投稿記事 by tk-xleader » 17年前

両方のヘッダーファイルに定義しているからエラーがでます。

片方の構造体を削除し、ヘッダーファイルの先頭に

#include"削除しなかったほうのヘッダーファイル"

としてください。

chunezu

Re:ヘッダファイル

#4

投稿記事 by chunezu » 17年前

やってみました。
/*extern.h*/
#include "kouzou.h"

extern Player nz;

extern Tama t;


/*kouzou.h*/
typedef struct{
        double x,y,size;
		int	flag;
		double angle;
}Player;

Player nz;


typedef struct{
		int flag,pattern;
		int x,y,size;
}Tama;

Tama t;

 "struct Player nz" (?nz@@3UPlayer@@A) は既に main.obj で定義されています。
 "struct Tama t" (?t@@3UTama@@A) は既に main.obj で定義されています。
1 つ以上の複数回定義されているシンボルが見つかりました。
とでてきてしまいます。

もしかしたらソースに問題があるかもしれないので長くなりますがソースも載せておきます。

/*main.cpp*/
#include "DxLib.h"
#include <math.h>
#include "extern.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
        ChangeWindowMode(TRUE);
        if( DxLib_Init()==-1)return -1;
        SetDrawScreen(DX_SCREEN_BACK);

	extern void fps();
	extern void fpscolor();
	extern void enemy1();

	
		int image[2];
		char Key[256];
		int GHandle;

		nz.x=320;
		nz.y=120;
		nz.angle=180;
		nz.size=10;
		nz.flag=1;

		// 読み込み
		GHandle=LoadGraph("nz.png");
		LoadDivGraph("back.png",2,2,1,640,480,image);
		fpscolor();

        while(!ProcessMessage() && !ClearDrawScreen())
        {
			GetHitKeyStateAll(Key);

			int RefreshTime;
			RefreshTime=GetNowCount();


			//左回転	 
			if(Key[KEY_INPUT_LEFT]==1){
					nz.angle=nz.angle+10;
			//回転に制限
			if(nz.angle>=250){nz.angle=250;}
			}


			//右回転
			if(Key[KEY_INPUT_RIGHT]==1){
				nz.angle=nz.angle-10;
			//回転に制限
			if(nz.angle<=120){nz.angle=120;}
			}


			//自機移動
			nz.x=nz.x+sin((3.141592/180.0)*nz.angle)*5;

			//左の壁に当たって勝手に曲がる
			if(nz.x<=130){
				nz.x=130;
				nz.angle=nz.angle-10;
				if(nz.angle<=180){nz.angle=180;}
			}

			//右の壁に当たって勝手に曲がる
			if(nz.x>=510){
				nz.x=510;
				nz.angle=nz.angle+10;
				if(nz.angle>=180){nz.angle=180;}
			}

				//背景
				DrawGraph(0,0,image[1],FALSE);
				DrawGraph(0,0,image[0],TRUE);


				enemy1();
			
				//自機
				if(nz.flag==1){DrawRotaGraph(nz.x,nz.y,1,3.141592/180.0*nz.angle,GHandle,TRUE);}

				//FPS
				fps();

				ScreenFlip();

			 while(GetNowCount()-RefreshTime<17);
		
		}

        DxLib_End();           // DXライブラリ使用の終了処理
        return 0;              // ソフトの終了
}

/*enemy.cpp*/
#include "DxLib.h"
#include "extern.h"

int tHandle = LoadGraph("nz.png"); 
	int count=0;

void enemy1(){

		count++;

		DrawFormatString(0,0,GetColor(255, 255, 255),"%d",count);

		{
			if (t.flag==1&&t.pattern==1){
				t.y=t.y+5; 
			}

			switch (count)
			{
			case 60: 
				count = 0;		//出現して何カウント目か測るカウンター初期化 
				t.flag = 1;		//出現フラグを立てる 
				t.pattern = 1;	//どういう軌道を描くか 
				t.x = 100.0;	//xの初期座標 
				t.y = 100.0;	//yの初期座標 
				t.size = 10;	//敵の大きさ 
				break; 
			default:
				break;
			}

			if (t.flag == 1){
				DrawRotaGraph(t.x,t.y,t.size,0,tHandle,TRUE );
			} 
}
}

/*fps.cpp*/
#include "DxLib.h"

int counter=0,FpsTime[2]={0,},FpsTime_i=0;
int color_white;
double Fps=0.0;
char Key[256];

void fpscolor(){
        color_white = GetColor(255,255,0);            //白色ハンドルを取得
        return;
}

void fps(){
        if(FpsTime_i== 0)
                FpsTime[0]=GetNowCount();               //1周目の時間取得
        if(FpsTime_i==49){
                FpsTime[1]=GetNowCount();               //50周目の時間取得
                Fps = 1000.0f / ((FpsTime[1] - FpsTime[0]) / 50.0f);//測定した値からfpsを計算
                FpsTime_i=0;//カウントを初期化
        }
        else
                FpsTime_i++;//現在何周目かカウント
        if(Fps != 0)
                DrawFormatString(565,460,color_white,"FPS %.1f",Fps); //fpsを表示
        return;
}
長々と申し訳ないです・・・
ご教授願います。

Re:ヘッダファイル

#5

投稿記事 by » 17年前

>"struct Player nz" (?nz@@3UPlayer@@A) は既に main.obj で定義されています。
>"struct Tama t" (?t@@3UTama@@A) は既に main.obj で定義されています。

同じ名前が存在するのが問題なので、同じ名前を使わないように
って意味ですね。
externの使い方が違ったりするのかな?
<pre></pre>でくくられてないのでソース見てませんが。

box

Re:ヘッダファイル

#6

投稿記事 by box » 17年前

> "struct Player nz" (?nz@@3UPlayer@@A) は既に main.obj で定義されています。
> "struct Tama t" (?t@@3UTama@@A) は既に main.obj で定義されています。

enemy.cpp のコンパイル時に、このメッセージが出ますか?

chunezu

Re:ヘッダファイル

#7

投稿記事 by chunezu » 17年前

それぞれを別々にコンパイルした時にはエラーは出ませんでした。

いっぺんにビルドするとエラーが起こるようです。

box

Re:ヘッダファイル

#8

投稿記事 by box » 17年前

main.cpp と enemy.cpp の双方で extern.h をインクルードしていますので、
結果として、2つの cpp ファイルで kouzou.h をインクルードしていることになります。

そうすると、main.cpp と enemy.cpp の双方で、外部変数 nz と t の実体を
定義しようとします。
外部変数の実体を定義するのは、プログラム全体のどこか1箇所でなければなりません。

tk-xleader

Re:ヘッダファイル

#9

投稿記事 by tk-xleader » 17年前

一般的には、ヘッダーファイルの中身を以下でくくる方法があります。

#ifndef HEADER_H_ONCE /*※ヘッダーファイル特有の名前(つまりヘッダーごとに適当に決めればよい)*/
#define HEADER_H_ONCE /*※と同一*/

/*ヘッダーファイルの内容を書く*/

#endif /*どのifndefに対応しているかコメントを残すといいのではないでしょうか*/

コンパイラなどが変わると使えませんがVCではヘッダーファイルの先頭に以下の記述をする方法もあります。

#pragma once

インクルードガードをつけないと構造体の定義で二重定義してしまう事になります。

tk-xleader

Re:ヘッダファイル

#10

投稿記事 by tk-xleader » 17年前

後、グローバル変数はその定義用のソースファイルを用意するというのも一つの手ではないでしょうか。
ある意味でまとまるのかもしれません。

管理人

Re:ヘッダファイル

#11

投稿記事 by 管理人 » 17年前

早いとこなんとかしないといけませんね、すみません(_ _|||)

あのコードは、なるべく入門時に見ないような構文はかかないようにして作ったので余計に変に難しくなってしまっています。
本来書くべき方法ではありません。
私も理想のかき方というものはよく知りませんが、私のやっている方法を紹介します。
いちいち
=========GlobalVariable.h============ 
の中身も
===========ExternGV.h============= 
の中身もかえるのめんどくさいですよね。

構造体は他のヘッダファイルにかいてもいいですし、全部一つにまとめたければ
こちら、変更が一度で済む方法があるので、よければご参考下さい。

まず、main関数のあるファイルの一番最初に

#define GLOBAL_INSTANCE

と書き、他のファイルにはこれを書きません。
そしてGlobalVariable.h内で、

#ifdef GLOBAL_INSTANCE
#define GLOBAL
#else
#define GLOBAL extern 
#endif

と書きます。
この意味は
「
main関数のあるファイルからこのヘッダファイルが呼ばれたときは、
「GLOBAL」という文字列は「空白」に置き換えて、

他のファイルからこのヘッダファイルが呼ばれたときは、
「GLOBAL」という文字列は「extern」という文字列に置き換えてね
」
という意味になります。

だから、これからは、全てのファイルからGlobalVariable.hを呼び、
ExternGV.hは使わないので削除してOKです。

今までGlobalVariable.hで

int func_state;

などと宣言していた部分は

GLOBAL int func_state;

に置き換えてください。オートで必要に応じてexternにしてくれる仕様になり便利です。
こうすると、宣言と同時に値代入が出来なくなるので注意してください。

GLOBAL int func_state=2;

などと書くとエラーになります。これは

extern int func_state=2;

が出来ないのと同じ理由です。
定義で、

#define GLOBAL_VAL(v)	=(v)

などを用いれば出来ることは出来るのですが、
値の初期化は初期化関数を作って行ったほうがいいので、
自然と宣言と同時に値格納は使わなくてもよくなると思いますので・・。

構造体は、このファイルに普通に書いていただければOKです。

つまりまとめますと、GlobalVariable.h内で、functionというグローバル変数宣言と、
x,yを持ったptという構造体を定義したければ


#ifdef GLOBAL_INSTANCE
#define GLOBAL
#else
#define GLOBAL extern 
#endif

GLOBAL int function;

typedef struct{
    int x,y;
}pt_t;


こんな感じになります。
 
 
ExternGV.hは削除します。

レイ

どなたかよろしくお願いします☆

#12

投稿記事 by レイ » 17年前

メモ帳でC言語のソースを作り、ソースのある場所に「これはブドウです。」という文を入れコマンドプロンプトでそのファイルを起動させると 「意味不明な語句 ブドウ」と出力し、エンターを押すと1.野菜 2.果物 の選択肢が出力され 2.を押しエンターを押すと「登録されました」と出力されるプログラムをつくりたいのですが、どなたかわかる方よろしくお願いします(^^)☆

バグ

Re:どなたかよろしくお願いします☆

#13

投稿記事 by バグ » 17年前

質問の意味がよく分かりません…(@_@;)

>>メモ帳でC言語のソースを作り、ソースのある場所に「これはブドウです。」という文を入れコマンドプロンプトでそのファイルを起動させると…

1:ソースを作るだけなのですか?コンパイルしたりはしないのでしょうか?もし、実行ファイルを作成するならば開発環境を提示してください。

2:『そのファイル』とはどのファイルでしょうか?

3:『ファイルを起動させる』というのがどういう事でしょうか?


>>「意味不明な語句 ブドウ」と出力し、エンターを押すと1.野菜 2.果物 の選択肢が出力され 2.を押しエンターを押すと「登録されました」と出力されるプログラムをつくりたいのですが、どなたかわかる方よろしくお願いします(^^)☆


もう少し詳しい状況説明をよろしくお願いします(^^)☆

しりうす~

Re:どなたかよろしくお願いします☆

#14

投稿記事 by しりうす~ » 17年前

ん?
名前変わってらっしゃるみたいですけど、先週の問題はもう解決したんでしょうか?
先週の問題解決してるなら、コマンドプロンプトからの起動くらいしか躓きそうな所は無いと思うのですが。

レイ

Re:どなたかよろしくお願いします☆

#15

投稿記事 by レイ » 17年前

バグさんへ☆
ソースを作り、メモ帳に「これはブドウです」で保存し、コマンドプロンプトでコンパイルし起動させ保存したファイル名を入力すると「意味不明な語句 ブドウ」と出力させたいです。で、エンターを押すと1.野菜 2.果物 の選択肢が出力され 2.を押しエンターを押すと「登録されました」と出力されるプログラムをつくりたいです。
しりうす~さんへ☆
解決いたしました!

たかぎ

Re:どなたかよろしくお願いします☆

#16

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

> ソースのある場所に「これはブドウです。」という文を入れ

ソースファイルが存在するディレクトリの意味ですか?
ソース中の特定の箇所の意味ですか?

> コマンドプロンプトで

このコマンドプロンプトは、Windowsのcmd.exeの意味ですか?
あるいは一般的なhttp://ja.wikipedia.org/wiki/%E3%82%B3% ... 7%E3%83%88の意味ですか?

> そのファイルを起動させると

インタープリタか何かで起動させるのでしょうか?
コンパイルするという意味でしょうか?
あるいは、もっと別の意味でしょうか?

>  「意味不明な語句 ブドウ」と出力し、
> エンターを押すと1.野菜 2.果物 の選択肢が出力され
> エンターを押すと「登録されました」と出力される

どこに、出力するのでしょうか?

> 2.を押し

「2.」というキーか何かがあるプラットフォームなのでしょうか?

> どなたかわかる方よろしくお願いします(^^)☆

今のままでは残念ながら分かりません。
多分こうだろうと解釈したソースを貼っておきます。
#include <stdio.h>
#include <stdlib.h>

/* 「これはブドウです。」 ← ある場所 */

int main(void)
{
  puts("「意味不明な語句 ブドウ」");

  int c = getchar();
  if (c != '\n') return EXIT_FAILURE;
  puts("1.野菜 2.果物");

  char s[sizeof("2.") + 1];
  char format[256];
  sprintf(format, "%%%us%%c", sizeof(s));
  scanf(format, s, &c);
  if (c != '\n') return EXIT_FAILURE;
  puts("「登録されました」");

  return EXIT_SUCCESS;
}
全く自信はありません。

バグ

Re:どなたかよろしくお願いします☆

#17

投稿記事 by バグ » 17年前

つまり…

1:あらかじめ『これはブドウです』と入力されたテキストファイルを作成しておく
2:プログラムを実行すると、文字の入力待ち状態になる
3:入力された文字が1で作成されたファイルのパスであれば『これはブドウです』という文字列から『ブドウ』というキーワードを抜き出して『意味不明な語句 ブドウ』と表示する
4:エンターが入力されるまで待ち、『1.野菜 2.果物』と画面に表示して1か2を入力させる
5:2を選択した場合に『登録されました』と表示する

という流れでよいのでしょうか?

たかぎ

Re:どなたかよろしくお願いします☆

#18

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

一部修正します。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* 「これはブドウです。」 ← ある場所 */

int main(void)
{
  puts("「意味不明な語句 ブドウ」");

  int c = getchar();
  if (c != '\n') return EXIT_FAILURE;
  puts("1.野菜 2.果物");

  char s[sizeof("2.") + 1];
  char format[256];
  sprintf(format, "%%%us%%c", sizeof(s));
  scanf(format, s, &c);
  if (strcmp(s, "2.") != 0 || c != '\n') return EXIT_FAILURE;
  puts("「登録されました」");

  return EXIT_SUCCESS;
}
いずれにせよ、自信はありません。

レイ

Re:どなたかよろしくお願いします☆

#19

投稿記事 by レイ » 17年前

バグさんへ
あ、その通りです(^^;)…

しりうす~

Re:どなたかよろしくお願いします☆

#20

投稿記事 by しりうす~ » 17年前

課題の意図をまるっきり無視して作るなら、たかぎさんの載せて下さっているプログラムにファイル名("これはブドウです。"と書いたファイル名をソースにべた書きで)の判定を入れれば完成ですw

課題の意図を汲むと"これはブドウです。"の文章から"ブドウ"を切り出す際の条件が無いと、プログラムが組みにくいのかな("ブドウ"が出るまで文字列比較で良いとはいえ、汎用性考える人からすると。発展系で"オレンジ"とかもありそうですし)。

前回の問題で文字の入出力はできてるみたいですので、もう少しですね。
頑張ってください。

レイ

Re:どなたかよろしくお願いします☆

#21

投稿記事 by レイ » 17年前

たかぎさんへ
ありがとうございます。自分の最終的目標は、ワードやメモ帳などの文章から、名詞や専門用語を抜き出すプログロムを作ることです。そして、抜き出された語句を表示し、自分が数字キーをたたいて 車 人 モノ 植物などに振り分け登録、保存しコンピュータが日々知識を蓄え文字で会話できるようなプログラムをつくりたいです☆
今後ともよろしくお願いします(^^)

たかぎ

Re:どなたかよろしくお願いします☆

#22

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

最初の質問内容からは予想もつかない話になっていますが...

自然な文を解析するには、「形態素解析」について調べるとよいでしょう。
「茶筌」というツールないしはライブラリがありますので、使えるかもしれません。

はいぜる

Re:どなたかよろしくお願いします☆

#23

投稿記事 by はいぜる » 17年前

正直なところ面白半分でみていましたが(失礼)

>>コンピュータが日々知識を蓄え文字で会話できるようなプログラム
というのには少し興味をいだきました。
がんばってください(・・b

やそ

Re:どなたかよろしくお願いします☆

#24

投稿記事 by やそ » 17年前

車に搭載してKIT2000(ナイトライダー)のようにおしゃべりしたいね^^

しりうす~

Re:どなたかよろしくお願いします☆

#25

投稿記事 by しりうす~ » 17年前

http://www.din.or.jp/~ohzaki/uzura.htmget=

こんなのもありましたねぇ。
利用者の話題が特定の分野に偏ると、なかなか笑える発言がされてたり。

閉鎖

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