struct と extern の使い方について

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

struct と extern の使い方について

#1

投稿記事 by 太郎 » 16年前

お初にお目に掛かります、太郎と申します。

最近「独習C」と言う
ハーバート・シルト著の参考書を読みながら
プログラムをパチパチ打っています。
C言語暦は1ヶ月位で、基本構文を覚えた位です。
それらをどう組み合わせて使ったら良いのか、までは
まだ大きな物を作った事が無いので分かりません。

そして、最近ぶっつけ本番で
DXライブラリを使ったゲームを作り出しました。

今回難儀している所は
「structをexternするにはどうすれば良いんだろう!?」
です。独習Cにも分割コンパイルの方法は
externを使え位しか記載されていなくて?
普通に
extern struct Test{
	int a;
	int b;
	int c;
}tt;
とやってもコンパイラがエラーを出して来ます。

さっき難儀しながら現在作っているゲームのソースと同じ感じで
まずい部分をピックアップしたプログラムを作って見ました。
────────────────
[ Player.h ]

#pragma once

extern struct tt TEST;

void Stick(void);

────────────────
[ Player.cpp ]

#include"Player.h"

void Stick(void)
{
	TEST.a=20;
	TEST.b=30;
	TEST.c=40;
	
}

────────────────
[ Test.h ]

#pragma once
#include<stdio.h>


struct Test{
	int a;
	int b;
	int c;
}tt;

#include"Player.h"

────────────────
[ Main.cpp ]

#include<stdio.h>
#include"Test.h"

int main(void)
{
	a=10;
	b=20;
	c=30;
	
	return 0;
}

────────────────
このソースを実行すると下記のエラーが出ます。
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
Player.h:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
Error: 外部シンボル '_main' が未解決(C:\BORLAND\BCC55\LIB\C0X32.OBJ が参照)

質問をまとめてみますと
structをexternするにはどうすれば良いのでしょうか。

環境は下記の通りです。

OS:WindowsXPpro SP3
コンパイラ:Borland C++ 5.5.1
ライブラリ:DXライブラリ

御津凪

Re:struct と extern の使い方について

#2

投稿記事 by 御津凪 » 16年前

エラー内容自体は全く別のエラーです。
どうやら単体のソースでコンパイルしようとしていますね。
(Player.cpp のみをコンパイルしている)
bcc32 Main.cpp Player.cpp
としてコンパイルするファイルを並べて、コンパイルを実行してみてください。
ただし、 Main.cpp で定義されていない変数が使用されているのでエラーが出ますが。


extern の基本的な使い方としては、

・ヘッダファイルで extern をつけた変数を書いておく。(その変数がありますよという指示)
・どれか一つのソースファイルに extern のつけていない変数を書く。(実際の変数の定義)

となります。
今回の場合、構造体なので、ヘッダファイルで、

typedef struct Test{
    int a;
    int b;
    int c;
}tt;

と構造体 tt を定義し、
そのあとに、

extern tt TEST;

と extern で変数の存在を知らせます。(このときは実体化していない)

そして、どれか一つのソースファイル内に、

tt TEST;

と書けば、変数の存在が確定します。
(構造体 tt の定義のため、ヘッダファイルを事前にインクルードすること)
ちなみに、複数のソースでextern されている同名のグローバル変数を書くと、
リンク時に複数存在しますとエラーが出ます。

太郎

Re:struct と extern の使い方について

#3

投稿記事 by 太郎 » 16年前

>御津凪さん

優しくて丁寧な返信を本当にどうもありがとうございました。

先程、VC2008の方で作り直してコンパイルして見ました。
ちょっとだけ中身を変えて僕の理解の通りに
ソースを改変した所、更にエラーが出てしまいました。

下記がそのソースとエラーログです。
────────────
[ Test.h ]

#pragma once
#include<stdio.h>

typedef struct Test{
	int a;
	int b;
	int c;
}tt;

#include"Player.h"

────────────
[ Player.h ]

#pragma once

extern tt TEST;

void Stick(void);

────────────
[ Player.cpp ]

#include"Player.h"

void Stick(void)
{
	TEST.a=20;
	TEST.b=30;
	TEST.c=40;	
}

────────────
[ Main.cpp ]

#include<stdio.h>
#include"Test.h"

tt TEST;

int main(void)
{
	TEST.a=10;
	TEST.b=20;
	TEST.c=30;

	Stick();

	return 0;
}

─────────────
[ エラーログ ]

1>------ すべてのリビルド開始: プロジェクト: テスト, 構成: Debug Win32 ------
1>プロジェクト 'テスト'、構成 'Debug|Win32' の中間出力ファイルを削除しています。
1>コンパイルしています...
1>Main.cpp
1>Player.cpp
1>player.h(3) : error C2146: 構文エラー : ';' が、識別子 'TEST' の前に必要です。
1>player.h(3) : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
1>player.h(3) : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
1>player.cpp(5) : error C2228: '.a' の左側はクラス、構造体、共用体でなければなりません
1>        型は 'int' です。
1>player.cpp(6) : error C2228: '.b' の左側はクラス、構造体、共用体でなければなりません
1>        型は 'int' です。
1>player.cpp(7) : error C2228: '.c' の左側はクラス、構造体、共用体でなければなりません
1>        型は 'int' です。
では「TEST」が良くないのか、と思い

extern tt;

にすると今度は「左辺を無視します」と出てしまい
やっぱりこの行がエラーになってしまいます。

何故でしょう…。
やっぱりまだゲームを作るには早過ぎたんでしょう、多分orz。

たかぎ

Re:struct と extern の使い方について

#4

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

Player.cppからはPlayer.hを単独でインクルードしていますが、tt型の定義はTest.hでなければ行われません。
つまり、Player.cppではPlayer.hではなく、Test.hをインクルードすべきではないでしょうか?

ところで、「独習C」を使うのであれば、C++ではなくCとしてコンパイルすべきかと思います。
拡張子が.cppだとC++扱いになりますので、細かい点で言語仕様が異なります。
無用の混乱をさけるためにも、拡張子は.cppではなく.cにしておきましょう。

> やっぱりまだゲームを作るには早過ぎたんでしょう、多分orz。

残念ながらそうだと思います。
遠回りのようでも、もう少し基礎を固めましょう。

御津凪

Re:struct と extern の使い方について

#5

投稿記事 by 御津凪 » 16年前

解決策はたかぎさんの通りなので、エラーの意味と原因を書いておきます。


1>player.h(3) : error C2146: 構文エラー : ';' が、識別子 'TEST' の前に必要です。

この部分では、 tt という型はその時点では存在しないため、起きています。

1>player.h(3) : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません

これは上記のエラーのため、 TEST を int 型と仮定してコンパイルを続行します、という意味です。


1>player.cpp(5) : error C2228: '.a' の左側はクラス、構造体、共用体でなければなりません
1> 型は 'int' です。
1>player.cpp(6) : error C2228: '.b' の左側はクラス、構造体、共用体でなければなりません
1> 型は 'int' です。
1>player.cpp(7) : error C2228: '.c' の左側はクラス、構造体、共用体でなければなりません
1> 型は 'int' です。

これは、"型は 'int' です" とあるとおり、TEST が int 型と解釈されているため起きているエラーです。


元凶は tt の型が分からない点なので、先に tt の型を知らせる必要があります。


# たかぎさんの仰るように、C言語についてもう少し修行を積んでからのほうがいいと思います。
# 今のままでは完成もままならない可能性が高いので。

太郎

今後の学習方針で聞きたい事があります

#6

投稿記事 by 太郎 » 16年前

>たかぎさん

ちゃんと動かす事が出来ました!
どうもありがとうございました。

検索してC言語の講座サイト等を読むのですが
殆どが基礎の基礎の様な事しか書いて無くて
僕の知りたい情報がなかなかありません。
今後はどう言った感じで学習を進めて行けば良いでしょうか。

最終的には2Dのアクションゲームの様な物を
ライブラリを介せず作りたいと思っています。
あくまでそれは「最終的に」なので、取り合えず
次の一歩は何をすれば良いのかな…と悩み始めました。

たかぎ

Re:今後の学習方針で聞きたい事があります

#7

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

> 次の一歩は何をすれば良いのかな…と悩み始めました。

とりあえず、他の人が書いたソースを読んでみましょう。

太郎

無題

#8

投稿記事 by 太郎 » 16年前

>たかぎさん

すいません、かなり曖昧な質問をしてしまいました。
反省していますm(_ _)m

分かりました、他の人のソースを読む学習を
やって見ようと思います。

>御津凪さん

エラーログの読み方を教えて頂きありがとうございました。
なるほど、先に「tt」を定義しないと駄目なんですね。


二大先生、質問にお付き合い頂きありがとうございました。
一先ず解決と言う事で解決マーク付けて置きます。

minami

龍神録プログラミングの実行させてみようについて

#9

投稿記事 by minami » 16年前

龍神録プログラミングの実行させてみようの欄で詰まっています。
#define GLOBAL_INSTANCE 
#include "../include/GV.h"

int Key[256];

int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[/url]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key==1) GetHitKeyStateAll_InputKey++;
        else                            GetHitKeyStateAll_InputKey=0;
    }
    return 0;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    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が押されていない


        //ココ!!



        ScreenFlip();
    }

    DxLib_End();
    return 0;
}

ソースをそのまま貼り付けて実行させているのですが、

c:\dxlib_vc\1章\mydat\include\gv.h(1) : fatal error C1083: include ファイルを開けません。'../../../include/DxLib.h': No such file or directory
fps.cpp
c:\dxlib_vc\1章\mydat\include\gv.h(1) : fatal error C1083: include ファイルを開けません。'../../../include/DxLib.h': No such file or directory
ini.cpp
などと出て実行できません。どうすれば実行できるようになるのでしょうか。
環境は  
OS : Windows xp home
コンパイラ : VC++ 2008EE
です。DXライブラリなどの設定はうまくいってると思うんですが…

SooA

Re:龍神録プログラミングの実行させてみようについて

#10

投稿記事 by SooA » 16年前

丁度数日前に龍神録プログラミングを拝見させて頂いた所です。

龍神録では "../../../include/DxLib.h" で示すフォルダに
DXライブラリが入っている構成になっています。

一括ダウンロードした場合はこの構成になるので問題ありませんが、
ソースをコピペした場合はフォルダの構成が違ってくるので
GV.h 内の
[color=AAFFAA>#include "../../../include/DxLib.h"[/color]
を下記に変更しましょう。
[color=AAFFAA>#include "DxLib.h"[/color]

minami

Re:龍神録プログラミングの実行させてみようについて

#11

投稿記事 by minami » 16年前

返信ありがとうございます。
言われた通りに変更したところ、実行することができました。
適格なアドバイスありがとうございました。

閉鎖

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