Iii v
This presentation is the property of its rightful owner.
Sponsored Links
1 / 20

プロジェクト演習 III,V <インタラクティブ・ゲーム制作> プログラミングコース PowerPoint PPT Presentation


  • 79 Views
  • Uploaded on
  • Presentation posted in: General

プロジェクト演習 III,V <インタラクティブ・ゲーム制作> プログラミングコース. 第 5 回 グローバル変数とファイル分割と コンパイルの割と根本的な話. 今日のメニュー. グローバル変数の安全な使い方 リフスローの発表のフォローアップ的内容 あまり使うことをおすすめはしませんが、 必要悪な場合もあるので覚えておこう ファイル分割とコンパイルの関係 根本から理解していないと誤解を引きずるので丁寧に話します. 嫌われがちだけど、必要な時もあるんだよ?. グローバル変数の安全な使い方. グローバル変数とは. どの関数からでもアクセスできる変数

Download Presentation

プロジェクト演習 III,V <インタラクティブ・ゲーム制作> プログラミングコース

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Iii v

プロジェクト演習III,V<インタラクティブ・ゲーム制作>プログラミングコース

第5回

グローバル変数とファイル分割と

コンパイルの割と根本的な話


Iii v

今日のメニュー

  • グローバル変数の安全な使い方

    • リフスローの発表のフォローアップ的内容

    • あまり使うことをおすすめはしませんが、必要悪な場合もあるので覚えておこう

  • ファイル分割とコンパイルの関係

    • 根本から理解していないと誤解を引きずるので丁寧に話します


Iii v

嫌われがちだけど、必要な時もあるんだよ?

グローバル変数の安全な使い方


Iii v

グローバル変数とは

  • どの関数からでもアクセスできる変数

  • あまり利用は推奨されないが、「定数」を定義する際にはよく使われる

  • 先週のコードレビューで2つのヘッダに分割して定義と宣言を行っていたが、あの利用方法には若干問題がある

    • どちらもヘッダになっているので分離している意味が無い


Iii v

グローバル変数もお品書き(宣言)と実体(定義)に分けよう

Global.h

Global.cpp

#include “Global.h”

const int WIDTH = 800;

const int HEIGHT = 600;

void procGlobalFunc(void)

{

// 処理実体を記述

return;

}

#pragma once

extern const int WIDTH;

extern const int HEIGHT;

void procGlobalFunc(void);


Iii v

ポイント

  • ヘッダでは型名の前にexternを付けて、変数の型と名前だけを「宣言」する

    • externを付けると「実体は他にある変数の宣言だけするよ」という意味になる

  • 実体を書くためのcppを用意し、extern宣言を書いたヘッダをインクルードしてから、変数の実体を「定義」する

    • 定数なら定数値の代入も行っておく

  • 同様の手順で関数も宣言、定義が可能

    • 関数の場合は宣言側のexternは不要


Iii v

使用上の注意点

  • 基本的に「定数」しか使わないのが無難

    • 変数をあちこちからいじるのは超危険

  • 間違っても「クラスオブジェクトの実体」をグローバルに置いてはいけない!

    • どうしても必要な場合はポインタをグローバルに置いて初期値をNULLにしておき、初回使用時にnewするようにして使う

    • デザインパターンのSingletonに近い考え方


Iii v

グローバルオブジェクト利用例

Global.h

Global.cpp

#include “Global.h”

GlobalHoge *g_hoge = NULL;

GlobalHoge* getHoge(void)

{

if(g_hoge == NULL) {

g_hoge =

new GlobalHoge();

}

return g_hoge;

}

#pragma once

#include “GlobalHoge.h”

/*

ポインタを返す関数を用意して、

ダイレクトに触らせない方が良い

*/

//extern GlobalHoge *g_hoge;

GlobalHoge* getHoge(void);


Iii v

ダメな理由

  • 以下の状況を前提とする

    • a.cpp、b.cppにそれぞれ「HogeAg_a」と「HogeBg_b」が定義されている

    • HogeAはHogeBの情報を利用する

      • つまりHogeAより先にHogeBのオブジェクトが作られていなければならない

  • このプログラムを実行した時、g_aとg_bのうち、どっちが先に生成されるか?

    • それは誰にも分からない


Iii v

C++(C)のコンパイルの仕組みについて述べます

定義と宣言の分離が必要な理由


Cpp exe

cppからexeまでの流れ

  • 各cppごとにインクルードを処理します

    • 実質的にやっているのは「コピペ」です

    • ヘッダファイルの内容をその場所に取り込んで、結果的に「宣言」を取り込むことになります

  • ヘッダを取り込んだcppを翻訳(コンパイル)して、中間ファイル(obj)にします

    • 文法間違い、未宣言のクラスや変数の使用はここで「コンパイルエラー」として弾かれる

  • 中間ファイルとライブラリを結合(リンク)して、実行ファイル(exe)にします

    • 利用するライブラリの指定ミスや、同名の関数や変数がかち合った場合は「リンカエラー」になる


Iii v

模式図

Hoge.h

Hoge.cpp

#include “Hoge.h”

Fuga.h

Hoge.h

Hoge.h

Hoge.cpp

Fuga.cpp

Fuga.h

#include “Hoge.h”

Fuga.cpp

#include “Fuga.h”

コンパイル

main.cpp

#include “Hoge.h”

#include “Fuga.h”

Fuga.h

Hoge.h

main.cpp


Iii v

コンパイル単位はcpp

  • ヘッダの内容はcppにインクルードされない限り、プログラムに何も影響も与えない

  • インクルードが済んだ時点で、利用するクラス、変数、関数の「定義か宣言」が含まれていないとエラーになる

    • 見えないものは使えない

  • 複数のcppそれぞれに「宣言」が含まれるのは問題ないが、「定義」がそれぞれで行われるとリンカエラーになる


Iii v

インクルードガードの意義

  • 「#pragma once」と書くか、右のようにすることで「1つのcppにおいてはそのヘッダが1回しかインクルードされない」ようにできる

  • 2つのヘッダが同じものをインクルードしようとしている際にガードすることができる

    • 模式図の例など

  • 異なるcpp間での多重定義は防げない

#ifndef __HOGE.H__

#ifdef __HOGE.H__

// ここにヘッダの宣言を書く

#endif

「#pragma once」が使えないコンパイラ

ではこちらの書き方を使う。

原理はプリプロセッサの仕組みを利用した

テクニックで、「__HOGE.H__」が定義

されていなければその文字列を定義した上で

宣言を展開する。一度でも宣言されていたら

それ以降はスキップする、というもの。


Iii v

もしヘッダに「定義」が含まれていたら?

Global.h

(実体付き)

  • グローバル変数の定義をヘッダでしてしまい、それを複数のcppで取り込むと、それぞれのcppごとに別々の変数が作られてしまう

    • そのcppの中でしか見えない変数になる

  • 定数値(const)なら大して問題にならないが、変数やオブジェクトの場合は致命傷になる

Fuga.h

Global.h

(実体付き)

Hoge.h

Hoge.h

Hoge.cpp

Fuga.cpp

Global.h

(実体付き)

Fuga.h

Hoge.h

main.cpp


Iii v

宣言と定義の分離

Global.h

(宣言)

  • cppに定義を記述することで、コンパイルされた際に実体が生成される

  • 他のcppからはヘッダの宣言を通じて、他のcppに記述された変数や関数、クラスを利用できる

Global.h

(宣言)

Fuga.h

Global.h

(宣言)

Global.cpp

(実体)

Hoge.h

Hoge.h

Hoge.cpp

Fuga.cpp

Global.h

(宣言)

Fuga.h

Hoge.h

main.cpp


Static

意味は単一でも用途が広くて説明に困る…

謎のキーワードstaticの正体


Static1

static、この説明の難しきもの

  • 一言で説明するのがとても難しい

    • 「スコープ内に静的な変数および関数を定義し、その唯一性を保証する」じゃ分からんでしょ?

  • なので、代表的な目的と用途を述べるに留めます


Static 2 1

staticの2大用途(+1)

  • クラスのメンバに付けて「インスタンスとは関係なく、クラスのスコープ内で共通の値を持った変数、関数を作る」時

  • ローカル変数に付けて「初期化は1回だけ、スコープを抜けても値が保持される変数にしたい」時

  • 1つのcppの中だけで扱いたいグローバル変数、関数を作りたい時

    • externなどで外部から宣言しても扱えなくする


Iii v

まとめ

  • とりあえずC++では「宣言」と「定義」に分けるのがいいらしい

  • VisualStudioでは「ビルド」の一言で済ましているけど、実は中では様々なドラマがあるらしい

  • extern、const、staticの用途はとりあえずバッチリ!

    • staticは今後必要に応じて掘り下げます


  • Login