ページ 1 / 1
struct と extern の使い方について
Posted: 2009年3月14日(土) 13:59
by 太郎
お初にお目に掛かります、太郎と申します。
最近「独習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 の使い方について
Posted: 2009年3月14日(土) 14:21
by 御津凪
エラー内容自体は全く別のエラーです。
どうやら単体のソースでコンパイルしようとしていますね。
(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 の使い方について
Posted: 2009年3月14日(土) 15:59
by 太郎
>御津凪さん
優しくて丁寧な返信を本当にどうもありがとうございました。
先程、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 の使い方について
Posted: 2009年3月14日(土) 16:11
by たかぎ
Player.cppからはPlayer.hを単独でインクルードしていますが、tt型の定義はTest.hでなければ行われません。
つまり、Player.cppではPlayer.hではなく、Test.hをインクルードすべきではないでしょうか?
ところで、「独習C」を使うのであれば、C++ではなくCとしてコンパイルすべきかと思います。
拡張子が.cppだとC++扱いになりますので、細かい点で言語仕様が異なります。
無用の混乱をさけるためにも、拡張子は.cppではなく.cにしておきましょう。
> やっぱりまだゲームを作るには早過ぎたんでしょう、多分orz。
残念ながらそうだと思います。
遠回りのようでも、もう少し基礎を固めましょう。
Re:struct と extern の使い方について
Posted: 2009年3月14日(土) 16:28
by 御津凪
解決策はたかぎさんの通りなので、エラーの意味と原因を書いておきます。
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言語についてもう少し修行を積んでからのほうがいいと思います。
# 今のままでは完成もままならない可能性が高いので。
今後の学習方針で聞きたい事があります
Posted: 2009年3月14日(土) 16:53
by 太郎
>たかぎさん
ちゃんと動かす事が出来ました!
どうもありがとうございました。
検索してC言語の講座サイト等を読むのですが
殆どが基礎の基礎の様な事しか書いて無くて
僕の知りたい情報がなかなかありません。
今後はどう言った感じで学習を進めて行けば良いでしょうか。
最終的には2Dのアクションゲームの様な物を
ライブラリを介せず作りたいと思っています。
あくまでそれは「最終的に」なので、取り合えず
次の一歩は何をすれば良いのかな…と悩み始めました。
Re:今後の学習方針で聞きたい事があります
Posted: 2009年3月14日(土) 17:16
by たかぎ
> 次の一歩は何をすれば良いのかな…と悩み始めました。
とりあえず、他の人が書いたソースを読んでみましょう。
無題
Posted: 2009年3月14日(土) 18:32
by 太郎
>たかぎさん
すいません、かなり曖昧な質問をしてしまいました。
反省していますm(_ _)m
分かりました、他の人のソースを読む学習を
やって見ようと思います。
>御津凪さん
エラーログの読み方を教えて頂きありがとうございました。
なるほど、先に「tt」を定義しないと駄目なんですね。
二大先生、質問にお付き合い頂きありがとうございました。
一先ず解決と言う事で解決マーク付けて置きます。
龍神録プログラミングの実行させてみようについて
Posted: 2009年3月27日(金) 03:52
by minami
龍神録プログラミングの実行させてみようの欄で詰まっています。
#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ライブラリなどの設定はうまくいってると思うんですが…
Re:龍神録プログラミングの実行させてみようについて
Posted: 2009年3月27日(金) 06:24
by SooA
丁度数日前に龍神録プログラミングを拝見させて頂いた所です。
龍神録では "../../../include/DxLib.h" で示すフォルダに
DXライブラリが入っている構成になっています。
一括ダウンロードした場合はこの構成になるので問題ありませんが、
ソースをコピペした場合はフォルダの構成が違ってくるので
GV.h 内の
[color=AAFFAA>#include "../../../include/DxLib.h"[/color]
を下記に変更しましょう。
[color=AAFFAA>#include "DxLib.h"[/color]
Re:龍神録プログラミングの実行させてみようについて
Posted: 2009年3月27日(金) 15:01
by minami
返信ありがとうございます。
言われた通りに変更したところ、実行することができました。
適格なアドバイスありがとうございました。