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

Slides:



Advertisements
Similar presentations
アルゴリズムとプログラミン グ (Algorithms and Programming) 第6回:クラスとインスタンス クラスの宣言 アクセス修飾子 インスタンスの生成 (new キーワード) this キーワード フィールドとメソッドの実際の定義と使い 方 クラスの宣言 アクセス修飾子 インスタンスの生成.
Advertisements

Item 1:View C++ as a federation of languages. C++ はただの ”C のクラスがあるバージョン ” ではない → 例外安全 (29 項 ) 、テンプレート (41 項 ) 、オーバーロード等の導入によりデザインや目指すコードが 変化している プログラミング言語はあくまで言語.
プログラミング 関数編 情報科学科. プログラミングにあたって C 言語では、 main 内に処理を記述 1000 行になるような大きなプログラムでは、 プログラム全体が何をしているのかを把握 することが困難になる 他人が見ると非常に理解しにくい 作成者であっても時が経てば内容を忘れて、他 人が見た時と同じ状況になる.
Boost. 勉強会 #6 札幌 ( ). 概要  主に cppll ML でご紹介してきた tips を C++ の仕様をより掘り下げた形でまとめ直し てみました。  今回は #include にフォーカスした内容です。 C++ Tips 1 #include 編 Boost.
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
1.1 C/C++言語 Hello.ccを作りコンパイルしてa.outを作り出し実行する
アルゴリズムとプログラミング (Algorithms and Programming)
プログラミング演習Ⅱ 第12回 文字列とポインタ(1)
プロジェクト演習III,V <インタラクティブ・ゲーム制作> プログラミングコース
プログラミング演習II 2004年12月 21日(第8回) 理学部数学科・木村巌.
社会人学習講座 「Javaプログラミング概論」
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
第20章 Flyweight ~同じものを共有して無駄をなくす~
プログラミング 3 構造体(1).
第10回 プログラミングⅡ 第10回
補足説明.
プロジェクト演習Ⅱ インタラクティブゲーム制作 イントロダクション2
プログラミング2 関数
暗黙的に型付けされる構造体の Java言語への導入
プログラミング応用 printfと変数.
ローカル変数とグローバル変数 ローカル変数  定義された関数内だけで使用できる変数 グローバル変数 プログラム全体で使用できる変数.
プログラミング 4 記憶の割り付け.
メモリの準備 メモリには、その準備の方法で2種類ある。 静的変数: コンパイル時にすでにメモリのサイズがわかっているもの。 普通の変数宣言
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
プログラミング言語論 第五回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第八回 知能情報学部 新田直也.
インタラクティブ・ゲーム制作 プログラミングコース 補足資料
岩村雅一 知能情報工学演習I 第12回(C言語第6回) 岩村雅一
プロジェクト演習III,V <インタラクティブ・ゲーム制作> プログラミングコース
C言語 はじめに 2016年 吉田研究室.
独習Java ・ 5.7  静的変数と静的メソッド ・ 5.8  ローカル変数と変数のスコープ  11月20日    小笠原 一恵.
アルゴリズムとプログラミング (Algorithms and Programming)
参照されないリテラル 長谷川啓
C#プログラミング実習 第3回.
計算機プログラミングI 第3回 プリミティブ値 クラスメソッド クラス変数 式と演算 変数の利用
サブゼミ第7回 実装編① オブジェクト型とキャスト.
第5回 プログラミングⅡ 第5回
オブジェクト指向言語論 第五回 知能情報学部 新田直也.
C プログラミング入門 基幹7 (水5) 14: 発展事項
JAVA入門⑥ クラスとインスタンス.
Make の使い方.
標準入出力、変数、演算子、エスケープシーケンス
cp-3. サブクラス,継承 (C++ オブジェクト指向プログラミング入門)
cp-2. 属性,アクセサ (C++ オブジェクト指向プログラミング入門)
cp-1. クラスとメソッド (C++ オブジェクト指向プログラミング入門)
モジュール分割.
岩村雅一 知能情報工学演習I 第12回(後半第6回) 岩村雅一
フレンド関数とフレンド演算子.
全体の流れ 画像ファイルを開き,画像データをメモリ上にロード メモリ上にロードした画像データに処理を加える
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
Javaとは Javaとはオブジェクト指向言語でJava VM(Java仮想マシン)と呼ばれるプログラム上で動作します。
2005年度 データ構造とアルゴリズム 第2回 「C言語の復習:配列」
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
情報処理Ⅱ 2005年11月25日(金).
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
14: 発展事項 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング演習II 2003年11月19日(第6回) 木村巌.
プログラミング演習II 2003年12月10日(第7回) 木村巌.
プログラミング演習II 2004年11月 2日(第3回) 理学部数学科・木村巌.
プログラミング入門2 第5回 配列 変数宣言、初期化について
プロジェクト演習III,V <インタラクティブ・ゲーム制作> プログラミングコース
C言語講座第5回 2017 構造体.
岩村雅一 知能情報工学演習I 第7回(後半第1回) 岩村雅一
プログラミング 3 ポインタ(1).
計算機プログラミングI 第2回 2002年10月17日(木) 履習登録 複習 ライブラリの利用 (2.6-7) 式・値・代入 (2.6-8)
計算機プログラミングI 第5回 2002年11月7日(木) 配列: 沢山のデータをまとめたデータ どんなものか どうやって使うのか
C プログラミング入門 総機1 (月1) 14: 発展事項
プログラミング 2 静的変数.
Presentation transcript:

プロジェクト演習III,V <インタラクティブ・ゲーム制作> プログラミングコース 第5回 グローバル変数とファイル分割と コンパイルの割と根本的な話

今日のメニュー グローバル変数の安全な使い方 ファイル分割とコンパイルの関係 リフスローの発表のフォローアップ的内容 あまり使うことをおすすめはしませんが、 必要悪な場合もあるので覚えておこう ファイル分割とコンパイルの関係 根本から理解していないと誤解を引きずるので丁寧に話します

嫌われがちだけど、必要な時もあるんだよ? グローバル変数の安全な使い方

グローバル変数とは どの関数からでもアクセスできる変数 あまり利用は推奨されないが、 「定数」を定義する際にはよく使われる 先週のコードレビューで2つのヘッダに 分割して定義と宣言を行っていたが、 あの利用方法には若干問題がある どちらもヘッダになっているので 分離している意味が無い

グローバル変数もお品書き(宣言)と実体(定義)に分けよう Global.h Global.cpp #pragma once extern const int WIDTH; extern const int HEIGHT; void procGlobalFunc(void); #include “Global.h” const int WIDTH = 800; const int HEIGHT = 600; void procGlobalFunc(void) { // 処理実体を記述 return; }

ポイント ヘッダでは型名の前にexternを付けて、 変数の型と名前だけを「宣言」する 実体を書くためのcppを用意し、extern宣言を書いたヘッダをインクルードしてから、 変数の実体を「定義」する 定数なら定数値の代入も行っておく 同様の手順で関数も宣言、定義が可能 関数の場合は宣言側のexternは不要

使用上の注意点 基本的に「定数」しか使わないのが無難 間違っても「クラスオブジェクトの実体」をグローバルに置いてはいけない! 変数をあちこちからいじるのは超危険 間違っても「クラスオブジェクトの実体」をグローバルに置いてはいけない! どうしても必要な場合はポインタをグローバルに置いて初期値をNULLにしておき、初回使用時にnewするようにして使う デザインパターンのSingletonに近い考え方

グローバルオブジェクト利用例 Global.h Global.cpp #pragma once #include “GlobalHoge.h” /* ポインタを返す関数を用意して、 ダイレクトに触らせない方が良い */ //extern GlobalHoge *g_hoge; GlobalHoge* getHoge(void); #include “Global.h” GlobalHoge *g_hoge = NULL; GlobalHoge* getHoge(void) { if(g_hoge == NULL) { g_hoge = new GlobalHoge(); } return g_hoge;

ダメな理由 以下の状況を前提とする このプログラムを実行した時、g_aとg_bのうち、どっちが先に生成されるか? a.cpp、b.cppにそれぞれ「HogeA g_a」と「HogeB g_b」が定義されている HogeAはHogeBの情報を利用する つまりHogeAより先にHogeBのオブジェクトが 作られていなければならない このプログラムを実行した時、g_aとg_bのうち、どっちが先に生成されるか? それは誰にも分からない

C++(C)のコンパイルの仕組みについて述べます 定義と宣言の分離が必要な理由

cppからexeまでの流れ 各cppごとにインクルードを処理します 実質的にやっているのは「コピペ」です ヘッダファイルの内容をその場所に取り込んで、結果的に「宣言」を取り込むことになります ヘッダを取り込んだcppを翻訳(コンパイル)して、中間ファイル(obj)にします 文法間違い、未宣言のクラスや変数の使用はここで「コンパイルエラー」として弾かれる 中間ファイルとライブラリを結合(リンク)して、実行ファイル(exe)にします 利用するライブラリの指定ミスや、同名の関数や変数がかち合った場合は「リンカエラー」になる

模式図 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

コンパイル単位はcpp ヘッダの内容はcppにインクルードされない限り、プログラムに何も影響も与えない インクルードが済んだ時点で、利用するクラス、変数、関数の「定義か宣言」が含まれていないとエラーになる 見えないものは使えない 複数のcppそれぞれに「宣言」が含まれるのは問題ないが、「定義」がそれぞれで行われるとリンカエラーになる

インクルードガードの意義 「#pragma once」と 書くか、右のようにすることで「1つのcppにおいてはそのヘッダが1回しかインクルードされない」ようにできる 2つのヘッダが同じものをインクルードしようとしている際にガードすることができる 模式図の例など 異なるcpp間での多重定義は防げない #ifndef __HOGE.H__ #ifdef __HOGE.H__ // ここにヘッダの宣言を書く #endif 「#pragma once」が使えないコンパイラ ではこちらの書き方を使う。 原理はプリプロセッサの仕組みを利用した テクニックで、「__HOGE.H__」が定義 されていなければその文字列を定義した上で 宣言を展開する。一度でも宣言されていたら それ以降はスキップする、というもの。

もしヘッダに「定義」が 含まれていたら? Global.h (実体付き) グローバル変数の定義をヘッダでしてしまい、それを複数のcppで取り込むと、それぞれのcppごとに別々の変数が作られてしまう そのcppの中でしか見えない変数になる 定数値(const)なら大して問題にならないが、変数やオブジェクトの場合は致命傷になる Global.h (実体付き) Fuga.h Hoge.h Hoge.h Hoge.cpp Fuga.cpp Global.h (実体付き) Fuga.h Hoge.h main.cpp

宣言と定義の分離 cppに定義を記述することで、コンパイルされた際に実体が生成される Global.h (宣言) cppに定義を記述することで、コンパイルされた際に実体が生成される 他のcppからはヘッダの宣言を通じて、他のcppに記述された変数や関数、クラスを利用できる Global.h (宣言) Global.h (宣言) Fuga.h Global.cpp (実体) Hoge.h Hoge.h Hoge.cpp Fuga.cpp Global.h (宣言) Fuga.h Hoge.h main.cpp

意味は単一でも用途が広くて説明に困る… 謎のキーワードstaticの正体

static、この説明の難しきもの 一言で説明するのがとても難しい なので、代表的な目的と用途を述べるに留めます 「スコープ内に静的な変数および関数を定義し、その唯一性を保証する」じゃ分からんでしょ? なので、代表的な目的と用途を述べるに留めます

staticの2大用途(+1) クラスのメンバに付けて「インスタンスとは関係なく、クラスのスコープ内で共通の値を持った変数、関数を作る」時 ローカル変数に付けて「初期化は1回だけ、スコープを抜けても値が保持される変数にしたい」時 1つのcppの中だけで扱いたいグローバル変数、関数を作りたい時 externなどで外部から宣言しても扱えなくする

まとめ とりあえずC++では「宣言」と「定義」に分けるのがいいらしい VisualStudioでは「ビルド」の一言で済ましているけど、実は中では様々なドラマがあるらしい extern、const、staticの用途はとりあえずバッチリ! staticは今後必要に応じて掘り下げます