お茶漬けびより

学んだことを整理する場所です。主に、C++, Unreal Engine 4 (UE4) を扱います。

抽象基本クラス(Abstract Base Class : ABC)の復習

ファクトリーメソッドを復習しようと思ったら、抽象基本クラスの復習をする羽目になったので、 調べて学んだことをメモ書きします。

抽象クラスとは

概念的なもの。このクラスから実態を持つことは出来ないが、抽象クラス型へのポインタと参照は使用できる。だそうです。

抽象クラス (C++)

実態を持たないので、継承しないと意味がありません。なので、抽象基本クラスとも言うそうです(自分が読んだ本には、抽象基本クラスと書いてあった)。今後、抽象基本クラスは ABC(Abstract Base Class) と表記します。

じゃあ、どういうものが ABC かというと、純粋仮想メンバ関数を持つクラスのことを ABC といいます。純粋仮想メンバ関数というのは、以下の様なものです。

virtual void Method() = 0;

純粋仮想メンバは、継承先で必ずオーバーライドしないといけません。つまり継承先で必ず実装しないといけません。ですが、ABC 側で実装をしてはいけないという意味ではありません。Method().cpp ファイルで実装するとコンパイルは通り、呼ぶことが可能です。

ABC は実態を持つことは出来ませんが、ABC 型へのポインタを作ることが可能です。
このポインタを使って、ABC を継承した様々なクラスのインスタンスへのポインタを入れることが出来ます。つまり、以下のように書きます。

IBase *instance = new Derived();

IBase は、ABC です。Derived は、 IBase を継承したクラスです。
instance->method() のように使えば、継承したインスタンスを呼ぶことが出来ます。上記は、Derived のみですが、他に IBase を継承したクラスがあれば、同じように使うことが出来ます。

コンストラクタ、デストラクタ

コンストラクタを仮想化することは出来ませんが、デストラクタは可能です。 つまり以下のように書けます。

virtual ~IBase();

これは、ABC で必ず必要になります。ABC は、実態を持つことはないので、必ず継承されて使われます。しかし、書かなくてもコンパイルは通ります。このときコンパイラは、デフォルトデストラクタを作成しますが、この状態で ABC を継承した Derived 型のポインタを delete すると、大変なことが起こります。コードで示すと以下のようになります(コンパイルは通らないかもしれません……)。

// 抽象基本クラス
class IBase
{
public:
    virtual void Method() = 0;
};
// 抽象基本クラスを継承したクラス
class Derived : public IBase
{
public:
    ~Derived(){};
    void Method() {};
};

int main()
{
    IBase *instance = new Derived();
    instance->Method();
    delete instance;
    
    return 0;
}

このとき、delete で呼ばれるデストラクタは、IBase のデフォルトデストラクタです。継承先のデストラクタは呼ばれません。どうしてかは詳しく説明できないですが、IBase のデストラクタが実態を持っていることが原因であることは分かると思います。 ですので、抽象基本クラスを作るときは、必ずデストラクタに virtual を付けるように気を付けましょう。

キーワード:override

デストラクタには virtual を付けるように気をつけましょうと言いましたが、このミスをコンパイル時に見つける方法があります。それが、override 指定子です。
こいつを付けることで、コンパイラに「今からオーバーライドするよ」と教えることが出来ます。つまり以下のようになります。

// 抽象基本クラスを継承したクラス
class Derived : public IBase
{
public:
    ~Derived() override {};
    void Method() {};
};

~Derived() の後に override を付けることで、コンパイル時にエラーが発生するようになります(Visual Studio 2017 だとコンパイルする前に赤い波線が出ました)。
もちろんデストラクタだけでなく、メソッドにも付けることが可能です。オーバーライドをするときには、必ず override を付けるようにしましょう。

override 指定子

キーワード:final

今度は、逆にオーバーライドをして欲しくないときの対処法です。override と同じようにメソッドの後ろに final を付けます。以下のようになります。

virtual int value() final { return value_; };

このように書くことで、継承先がオーバーライドをしようとすると、コンパイラはエラーを発します。処理が今後変わることがないときは、 final を付けるようにしましょう。

final 指定子

キーワード:delete

最後に delete を紹介します。これは、delete 演算子ではありません。何と言うのかちょっと調べただけでは分からないですが、このキーワードを使うことで、メソッドやコンストラクタ、デストラクタを削除することが出来ます。 以下のように書きます。

public:
IBase() = delete;

public 側で書くことをお勧めします。これはコンパイラが delete であるかどうかよりもアクセスの可否を先に見るためです。private で delete されたメソッドをユーザが使おうとすると メソッドが private であることだけをエラーとして吐くそうです。また他にも利点があるのですが、ここでのメインの話ではないので省きます。詳細は、Effective Modern C++ の項目 11 を見てください。

Effective Modern C++ ―C++11/14プログラムを進化させる42項目

Effective Modern C++ ―C++11/14プログラムを進化させる42項目

おわり

以上、抽象基本クラスの復習でした。 C++11 から使えるようになったキーワードを混ぜることで、安全に継承をすることが出来るようになりそうです。

ここで記載したコードは、以下に上げています。

github.com

最後に、参考にした(復習する羽目になった)書籍を貼っておきます。

C++のためのAPIデザイン

C++のためのAPIデザイン

DirectX 11 を始めました # 0

自分の調べた内容を整理するために、書き起こしてみました。
なるべく DirectX 初心者でも分かるように書きたいと思います。

今回は、DirectX や別のライブラリを紹介していきます。

DirectX って?

Microsoft が開発したゲームやマルチメディア処理用のグラフィックス API です。
PC でゲームをする人は、初めてゲームをするときに入れたことがあるかもしれません。開発者は、これを開発のために使います。
この DirectX には、WindowsWindows 7Windows 8.1, Windows 10 のように大きなバージョンごとに名前が少し変わります。
有名なところだと、DirectX 9.0, DirectX 11.0, DirectX 12 です。名前が変わるきっかけは、大きな機能が追加、変更されたりすると変わります。

Windows のバージョンによって、使える DirectX が決まります。 だいたい以下のようになっています。

Windows の対応している DirectX のバージョンは、Wikipedia や 公式サイトが詳しいです。

https://support.microsoft.com/ja-jp/help/179113/how-to-install-the-latest-version-of-directx Microsoft DirectX - Wikipedia

いくつか種類はありますが、要は DirectX を使えば、ゲームを作れるよということです。
ここでは、DirectX 11.0 を使いますがこれは、DirectX 11 がそこそこ新しくて、そこそこ学びやすいからです。 DirectX 12 は、新しいのですが難しくいきなり触るのは危険だからです。

本当に DirectX でいいの?

先に DirectX を使えばゲームを作れると書きましたが、これは現実的ではありません。
というのも、DirectX というのは、開発者がコンピュータグラフィックス(CG)を扱うための手段としては低レベルな API だからです。
ゲームを作るというのが目的であれば、DirectX を直接触る必要なく作ることが出来る API(ライブラリ)があります。

例えば、DXライブラリというゲームライブラリがありますが、これは DirectX の機能をゲームのために簡単に扱えるようにしたライブラリです。
他にも、openFrameworks や、SFMLCinderSiv3D などがあります。ライブラリとは少し異なりますが、Cocos2d-x というフレームワークもあります。

自分が使いたい言語(C や C++Java など)、環境(PC やスマフォ)、目的は何なのか。だいたいこの 3 つを決めた上で、先に挙げたようなライブラリを選択することをお勧めします(特に目的が大事です)。
各ライブラリの URL は面倒なので省きますが、検索すると別のライブラリの名前も出ることがあるので、一度自分の目的を明確にしてから調べてみるといいでしょう。

実は、先に挙げたライブラリ、自分はどれも使ったことがありません・・・・・・。ゲームを作ろうと DirectX 9.0 を少し触ったことがあり、簡単なゲームを一つ作りましたが、かなり時間がかかりました(だらだらやっていたせいもありますが)。

調べた感じだと、
Cocos2d-xDXライブラリ や openFrameWorksDirectX や OpenGL
の順番で低レベルな API になっていくと思います。

じゃあ DirectX を使うメリットは何なのかといいますと、CG が描画される仕組みをより深く知ることができ、より自由で高速なプログラムを作ることが出来ます。ですが、自由で高速なプログラムなんて初心者には無理です。それなら初心者は、ライブラリで十分です。

ライブラリで十分なのですが、CG が描画される仕組みをより深く知ることができるのは、かなりのメリットだと思います。なので、DirectX を触ることは無駄ではないです。自分のしたいことと自由に使える時間と相談して、選んでいくといいと思います。

また、少しずつ低レベルな API に変えていくという方法もあると思います。
例えば、Cocos2d-x → DXライブラリ → DirectX というように使っている API に慣れたらさらに低レベルな API に切り替えて新しい(または同じ)ゲームを作っていくという方法です。
これは、ゲームで例えると自分があまり苦戦せずに倒せる敵でレベル上げをしていく感じです。逆にいきなり DirectX を触るのは、強敵や高経験値を持っているけど運要素が強い敵でレベル上げをしていくようなものです。

さいごに

長くなりましたが、なんとなく DirectX を触ってみようと考えていた方の参考になればいいなと思って書きました。

最後に、目的がゲームを作ることで、プログラミングなんてしたくないって方には、ゲームエンジンをおすすめします。
有名どころですと、UnityUnrealEngine があります。他にも XenkoDefold , Playground など様々なゲームエンジンが無料で扱えます。 どれも同じなわけではなくそれぞれに特徴があるので、これもまた自分の作りたいものに合わせて選ぶといいでしょう。あとは、使い方の情報の多さも大事です。

今回はこの辺でおしまいにします。

Re:ゼロから始めるポインタ入門 #2

ポインタの基礎からちょっとずつ難しくしていこうかと思っていたのですが、 それだと書きづらいので、もう好きなように書いていくことにしました。すみません……。

はじめに

今回からは、配列とポインタを関数の引数にするときの様々な方法を見ていきます。

仮引数が配列の関数に、配列を渡す

引数として渡す変数は以下のような配列です。

int array[ARRAY_LENGTH]; /* ARRAY_LENGTH は、定数 3 */

まず、実引数として配列を渡す方法を見ていきます。 以下のような関数を使います。

void ArrayPrint(int array[ARRAY_LENGTH]);

これを使う場合、以下のように配列を渡します。

#include <stdio.h>
#define ARRAY_LENGTH (3)

void ArrayPrint(int array[ARRAY_LENGTH]);

int main() {
    printf("Re:ゼロから始めるポインタ入門 #2\n");

    int array[ARRAY_LENGTH];
    int i;
    for (i=0; i<ARRAY_LENGTH; i++) {
        array[i] = i * i;
    }
    ArrayPrint(array);
    return 0;
}

void ArrayPrint(int array[ARRAY_LENGTH])
{
    int i;
    for (i=0; i<ARRAY_LENGTH; i++) {
        printf("array[%d]: %d\n", i, array[i]);
    }
    return;
}

初期化した array を引数として、関数 ArrayPrint() に渡して、ArrayPrint 内で printf を使って、array の中を出力しています。 結果は、以下のようになります。

Re:ゼロから始めるポインタ入門 #2
array[0]: 0
array[1]: 1
array[2]: 4

関数の引数と同じ配列を渡しているので、とくに何も考えずに使うことが出来ると思います。

追記

指摘を頂きました。
仮引数が要素数固定の配列でも、要素数が異なる配列を 渡すことが出来る。といった指摘です。 では、試してみましょう。

main 関数内で定義している array[ARRAY_LENGTH]array[3] にして、ARRAY_LENGTH の値を 10 にします。これでコンパイルをすると仮引数と実引数の要素数が異なるのですが、普通に通ってしまいます。実行すると以下のようになりました。

Re:ゼロから始めるポインタ入門 #2 指摘
array[0]: 0
array[1]: 1
array[2]: 4
array[3]: 0
array[4]: 0
array[5]: 0
array[6]: 1873092421
array[7]: 32708
array[8]: 0
array[9]: 0

思ってたよりは値がおとなしいですが、array[6]array[7] は、デタラメな値が入っていますね。上記のように、関数の仮引数に配列の要素数を指定してもコンパイルエラーを起こすことは出来ないようです。これは、仮引数に配列を指定しても、ポインタを指定したのと同じだからです。ただ、関数を以下のようにすれば一応、同じ配列の要素数ではないとコンパイルエラーを起こすことが出来ます。

void ArrayPrint(int (*array)[ARRAY_LENGTH])

関数を呼び出す時は、ArrayPrint(&array) のようにします。これは、多次元配列なので、以下のように書くことも出来ます。

void ArrayPrint(int array[][ARRAY_LENGTH])
void ArrayPrint(int array[2][ARRAY_LENGTH])

3つ書き方を示しましたが、どれも同じ意味です。こうすると今度は、行の指定を無視できるので、 結局、要素数の異なる配列を渡すことが出来てしまいます。
結論としては、関数の仮引数に配列を指定するのを止めて、次に説明するポインタとその要素数を指定する方法か、仮引数に配列を明記しつつ、内部の処理で配列の要素数が仕様で決めたものと異なる場合は、さっさとシステムを殺すように作るというのが解決策かなと思います(どなたか詳しい方いれば、ご指摘お願いします)。

追記は以上です。ご指摘ありがとうございました。 追記内容のコードは、以下に置いてあります。 github.com

仮引数がポインタの関数に、配列を渡す

次は、関数の仮引数が、ポインタの場合です。以下のような関数に配列を渡します。

void PointsPrint(int* points, size_t point_num) {
    int i;
    for (i=0; i<point_num; i++) {
        printf("points(%p): %d\n", points+i, *(points+i));        
    }
}

point_num には、引数の長さを渡します。 記事が長くなってしまうので、全文は避けますが、先ほど全文を載せたソースコードに、上記の関数 PointsPrint() を使います。渡す実引数は、先ほどと同じ array[ARRAY_LENGTH] です。
渡し方は、以下のようになります。

PointsPrint(array, ARRAY_LENGTH);

実行すると、以下のようになります。

Re:ゼロから始めるポインタ入門 #2
points(0x7ffff1384160): 0
points(0x7ffff1384164): 1
points(0x7ffff1384168): 4

array と書くことで、配列の先頭( array[0] )を渡すことになります。 配列は、同じ型のポインタが並んでいるみたいなものなので、関数 PointsPrint() のように ポインタとして扱えます。
ただ、配列のサイズが分からなくなってしまうので、引数として配列のサイズを受け取る必要があります。 逆に言えば、ポインタとして扱えば、どんなサイズの配列でも扱うことが出来るようになります。

今回は、以上です。 コードの全文は、以下に置いてあります。

github.com

C# と .Net Framework で 他の Windows アプリを操作するアプリ

簡単にですが作りました。

経緯

最近、C# を学び始めて .Net Framework を使うようになったのですが、これがけっこう便利で楽しくて、 ふと、WindowsAPI なら ハンドル取ってこれそうだなと思い、調べるとすでにやってる人がいたので、 マネをしてみました。

目的

アプリ一つ一つに割り当てられているハンドル(ウィンドウハンドル)を取得して、 外部のアプリからハンドル先に値を送ることでアプリを操作することが目的です。
まだ可能かどうかは分かりませんが、ゲームのテストや同じ操作の繰り返しをプログラムで 制御できればいいなと思って作りました。

こちらを参考にしたので、試したい方はこちらを見た方が早いかと思います。

普通、アプリだと複数のウィンドウやボタンがあるので、操作をするのは難しいのですが、 自分の場合は、ゲームの操作が目的だったので、ハンドルを取ってしまえばあとはコントローラの キーにあたる値を送ることで操作することが可能です。

操作するためのキーの値はこちらを見ればいいかと
Virtual-Key Codes (Windows)

環境

環境は以下です。

以下は、今回使う言語やフレームワーク、その他出てくる技術です。
もし読んでて分からないところがあれば、以下のキーワードを加えて検索するといいかも……?

GUI の作成

WPFGUI を作ります。 重要な部分ではないので飛ばします。以下のように作りました。

f:id:pickles-ochazuke:20170326231753p:plain

各ボタンの処理

Get Handle というボタンは、隣にある Process Name の入力内容を元に関係するアプリを探して、ウィンドウハンドルを取得します。Process Name は、タスクマネージャを開き、詳細タブに並んでいる .exe を除いたアプリの名前を入力します。

ボタン入力時の処理は以下です。

private void GetHandleButton_Click(object sender, RoutedEventArgs e)
{
    process = System.Diagnostics.Process.GetProcessesByName(ProcessName.Text);
    foreach (System.Diagnostics.Process ps in process) {
        LogBox.Text += ps.Id + ps.MainWindowTitle + ps.MainWindowHandle + "\n";
    }
}

GetProcessesByName でアプリのハンドルを取得します。 取得したら、内容をテキストボックスに出力します(これは確認用)。

Button というボタンは、Message の内容をハンドル先に送ります。つまり、Message に操作用の値を書き、 Button を押すことでアプリを操作します。が、これはまだ未実装です。現状は、予め用意した値を送るようにしています。

IntPtr hWnd = process[0].MainWindowHandle; 
LogBox.Text += SendMessage(hWnd, 0x0100, 0x20, 0x00);

SendMessage() で、どう操作したいかを指示しています。その後、確認用にテキストボックスに出力しています。 SendMessage(ハンドル, イベント, 内容1, 内容2) のように指定します。
イベントは、キーが押されたキーが離されたマウスのボタンがクリックされたなどです。内容1,2はイベントに合わせて指定します。何もない場合は 0x00 でいいと思います。 上記だと、hWnd に、スペースキー押されたという情報を送ります。 SendMessage は、.Net FrameworkAPI ではなく、Win32APIAPI です。これは、以下のように宣言することで使えるようになります。

[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);

DllImport という属性(Attribute)を使うことで、外部のライブラリを使えるようにしています。 ここら辺は、以下を参照してください。(正直、自分はちゃんと理解出来ていません……)

@IT:.NET TIPS Win32 APIやDLL関数を呼び出すには? - C#
キーワード:Attribute, Reflection, Annotation

これだけのコードで、別のアプリにプログラムで好きなキー入力を行うことができます。

コード

XAML 側のコードがないので、これだけでは動かないのですが、一応全文載せておきます。

using System;
using System.Windows;

namespace GetHandle
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        System.Diagnostics.Process[] process;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void GetHandleButton_Click(object sender, RoutedEventArgs e)
        {
            process = System.Diagnostics.Process.GetProcessesByName(ProcessName.Text);
            foreach (System.Diagnostics.Process ps in process) {
                LogBox.Text += ps.Id + ps.MainWindowTitle + ps.MainWindowHandle + "\n";

            }
        }

        private void MessageButton_Click(object sender, RoutedEventArgs e)
        {
            IntPtr hWnd = process[0].MainWindowHandle; 
            LogBox.Text += SendMessage(hWnd, 0x0100, 0x20, 0x00);
        }

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);
    }
}

デモ

Re:ゼロから始めるポインタ入門 #1

前回の続きです。

前回は、準備運動のようなものでしたが、 今回からはちゃんとポインタについて入門していきます。

まずポインタのことを知る前に、二つのことを知っておく必要があります。 16 進数とアドレスです。この二つを説明したあと、最後にポインタについて解説していきます。

16 進数

16 進数を知っている方は、読み飛ばして構いません。逆に知らない方は 2 進数のことを分かっておく必要があります。 2 進数については、前回に書いてあるので、そちらを参照してください。

16 進数とは、2 進数と 10 進数を知っているのであれば大方予想が着くと思いますが、16 の倍数で桁が増える表現方法です。 ですが、数字とは 0 ~ 9 の 10 個の数字です。残り 6 個はどうするかというと…… A ~ F を使います。10 進数では、9 の次が 10 で桁が増えますが、16 進数の場合は、9 の次は A になり桁は増えません。そこから B、C、D …… F と続きます。F は 10 進数で表すと値は何でしょう。数えてみましょう。 9、A(10)、B(11)、C(12)、D(13)、E(14)、F(15)。つまり F15 です。その次は基数の 16 なので、桁が一つ上がります。そう 10 になります。ところで 1010 進数の 10(十)なのか 16 進数 の 10(十六)なのか、2 進数の 10(二)なのか分かりづらいですね。 そこで、分かりやすいように手前に記号を付けます。2 進数の場合は、0b、 10 進数の場合は、0d、 16 進数の場合は 0x です。 b は binary(2 進数) の b。d は decimal(10 進数)の d。x は、Hexadecimal の x です(なんで h じゃないんだろう。hex が x に縮まったのかな……)。整理しましょう。

1000 という数字の手前に記号を付けます。説明のために数値は、10 進数に直しますが、数字だとややこしいので、漢字で解説します。
0b1000:これは、2 進数なので、ですね。
0d1000:これは、10 進数なので、です。
0x1000:これは、16 進数です。デカいですね。16 の 3 乗なので、四千九十六です。
どうでしょうか。整理できましたか? 16 進数は、慣れておくと便利なので、いろいろ自分で計算して練習してみましょう。

10 進数から 2 進数に変換し、2 進数から 16 進数への変換ができるのですが、これは、ネットや本に詳しく書かれているのでそちらを参照してください。

アドレス

では、アドレスについてです。前回、変数の話で値を保持するには器の大きさがあり、場所が必要だと書きました。この場所を管理するための番号があります。それがアドレスです。では、実際にアドレスを見てみましょう。アドレスを見るためには、変数の名前の前に &(アンパサンド) を付けます。

#include <stdio.h>

int main()
{
    int variable;

    printf("address of variable: %p\n", &variable);
    return 0;
}

上記を実行すると、以下のようにアドレスが表示されます。ただし、アドレスの値は毎回変わります。

address of variable: 0x7ffff409cbdc

これは、variable という器が 0x7ffff409cbdc の場所に保持されているということです。次に配列を作って、その配列のアドレスがどうなっているか見てみます。以下のプログラムを作成してください。

#include <stdio.h>
#define ARRAY_MAX (10)

int main()
{
    char array[ARRAY_MAX];
    int  aryi;

    for (aryi=0; aryi<ARRAY_MAX; aryi++) {
        printf("address of array[%d]: %p\n", aryi, &(array[aryi]));
    }
    return 0;
}

では、実行してみましょう。以下のようになりました。

address of array[0]: 0x7fffec172540
address of array[1]: 0x7fffec172541
address of array[2]: 0x7fffec172542
address of array[3]: 0x7fffec172543
address of array[4]: 0x7fffec172544
address of array[5]: 0x7fffec172545
address of array[6]: 0x7fffec172546
address of array[7]: 0x7fffec172547
address of array[8]: 0x7fffec172548
address of array[9]: 0x7fffec172549

アドレスのとこを見て下さい。各アドレスの下の位から 1~3 つ目まで見れば問題ありません。値が 1 ずつ増えてるのが分かります。char 型は、サイズが 1 Byte、つまり 8 bit です。つまり、このアドレスの単位は Byte のようです。試しに型を変えてみましょう。char 型から int 型にしてみると以下のようになりました。

address of array[0]: 0x7fffe297dc40
address of array[1]: 0x7fffe297dc44
address of array[2]: 0x7fffe297dc48
address of array[3]: 0x7fffe297dc4c
address of array[4]: 0x7fffe297dc50
address of array[5]: 0x7fffe297dc54
address of array[6]: 0x7fffe297dc58
address of array[7]: 0x7fffe297dc5c
address of array[8]: 0x7fffe297dc60
address of array[9]: 0x7fffe297dc64

4 ずつ増えていますね。(long)int 型は 4 Byte (処理系依存ですが、たいてい4 Byte だと思うのであまり言及しません)なので、アドレスの単位は Byte で正しそうです。

アドレスは場所を管理するための番号です。先ほどのプログラムの結果からアドレスは 型のサイズずつ管理しているということですね。

配列の結果を見ると分かりますが、変数は他の変数が占有している場所を利用して値を保持することはできません。中には共有する変数もありますが……今回は無視しましょう。基本的に変数が確保した場所は、その変数専用の場所になります。ですので、その変数が占有しているアドレスに訪れるとその変数の場所にたどり着くことができます。つまり、変数の場所が分かれば、その変数の中にある値を見たり、別の値を変数の中に入れたりできるわけです。そのための方法がポインタです。

ポインタの話に行く前に、一つ遊んでみましょう。何をするかというと足し算です。 以下を実行して下さい。

#include <stdio.h>
#define ARRAY_MAX (3)

int main()
{
    int array[ARRAY_MAX];
    int aryi;

    for (aryi=0; aryi<ARRAY_MAX; aryi++) {
        array[aryi] = aryi;
        printf("address of array[%d]: %p\n", aryi, &(array[aryi]));
    }
    printf("\n");

    printf("array[0] + 1\n");
    printf("%p + %d = %p\n", &(array[0]), 1, (&array[0]) + 1);

    return 0;
}

結果は以下のようになりました。

address of array[0]: 0x7fffe8de9180
address of array[1]: 0x7fffe8de9184
address of array[2]: 0x7fffe8de9188

array[0] + 1
0x7fffe8de9180 + 1 = 0x7fffe8de9184

array[0] のアドレス(0x7fffe8de9180)に 1 を加えると結果は、0x7fffe8de9184 になりました。なんと、4 も増えていますね。次に array の型を int から char にしてみましょう。 結果は、以下のようになりました。

address of array[0]: 0x7fffd307cf50
address of array[1]: 0x7fffd307cf51
address of array[2]: 0x7fffd307cf52

array[0] + 1
0x7fffd307cf50 + 1 = 0x7fffd307cf51

今度は、1 増えています。つまり型によって値の増え方が変わるというわけです。これで中途半端なアドレスを、簡単には指定できないようになってるわけですね。ちなみに、 printf 文内の足し算の処理を以下のようにすると、中途半端なアドレスが作れます。arrayint 型です。

(char*)(&array[0]) + 1

ですが、危険なのと特に意味はないので使う機会はないでしょう。

ポインタ

ポイント(point)という言葉があります。これは、点や先という意味もありますが、向けるや指さすという意味もあります。なのでポインタ(pointer)は、向ける者や指さす者という感じでしょうか。何に指さすかというとアドレスの中にあるモノです。ポインタが指さす先には、何かがあるわけです。実際にポインタを使ってみましょう。

#include <stdio.h>

#define ARRAY_MAX (3)

int main()
{
    int array[ARRAY_MAX];
    int aryi;

    for (aryi=0; aryi<ARRAY_MAX; aryi++) {
        array[aryi] = aryi;
        printf("address of array[%d]: %p\n", aryi, &(array[aryi]));
    }
    printf("\n");

    int* array_ptr;
    array_ptr = &array[0];

    printf("array_ptr has address of array[0]: %p\n", array_ptr);
    printf("array_ptr points %d\n", *array_ptr);

    return 0;
}

結果は以下のようになりました。

address of array[0]: 0x7ffff5947b90
address of array[1]: 0x7ffff5947b94
address of array[2]: 0x7ffff5947b98

array_ptr has address of array[0]: 0x7ffff5947b90
array_ptr points 0

array_ptr = &array[0] によって、ポインタ(array_ptr)に array[0] のアドレスを教えて、そのあとポインタが指し示す場所を見に行っています。*array_ptrで指している場所を見に行けるわけです。

アドレスの最後に足し算をしましたが、これを使えば配列の中を自由に見に行けます。 以下を実行してみましょう。

#include <stdio.h>

#define ARRAY_MAX (3)

int main()
{
    int array[ARRAY_MAX];
    int aryi;

    for (aryi=0; aryi<ARRAY_MAX; aryi++) {
        array[aryi] = aryi;
        printf("address of array[%d]: %p, %d\n", aryi, &(array[aryi]), array[aryi]);
    }
    printf("\n");

    int* array_ptr;
    array_ptr = &array[0];

    for (aryi=0; aryi<ARRAY_MAX; aryi++) {
        printf("array_ptr has address of array[%d]: %p\n", aryi, array_ptr + aryi);
        printf("array_ptr points %d\n", *(array_ptr+aryi));
    }
    return 0;
}

結果は、以下のようになりました。

address of array[0]: 0x7fffed9f3780, 0
address of array[1]: 0x7fffed9f3784, 1
address of array[2]: 0x7fffed9f3788, 2

array_ptr has address of array[0]: 0x7fffed9f3780
array_ptr points 0
array_ptr has address of array[1]: 0x7fffed9f3784
array_ptr points 1
array_ptr has address of array[2]: 0x7fffed9f3788
array_ptr points 2

配列の中を先頭から順番に見れているようです。実は、配列の各要素を指定するときのarray[i]は、*(array + i)の略なんですね。配列は、ポインタというわけです。[] を使わずに array とすると、配列 array の先頭のアドレスを指します。先頭のアドレスとは、&array[0] のことです。つまり array&array[0] は同じ意味です。整理しましょう。

以下は、int array[3] とした場合の説明です。

  • 配列は、ポインタの別の表現方法。
  • &array[0]array は同じアドレスを指す。
  • 配列の要素([] 内の値)は、配列の先頭からどれだけアドレスを増やすかを示すモノ。
  • array[i]*(array + i) は同じ意味。

確認してみましょう。

#include <stdio.h>
#define ARRAY_MAX (3)

int main()
{
    int array[ARRAY_MAX];
    int aryi;
    
    if (&array[0] == array) {
        printf("&array[0] == array\n");
    }

    if (&array[2] == array + 2) {
        printf("&array[2] == array + 2\n");
    }

    array[1] = 100;
    if (array[1] == *(array + 1)) {
        printf("array[1] == *(array + 1)\n");
    }

    return 0;
}

結果は、以下のようになりました。

&array[0] == array
&array[2] == array + 2
array[1] == *(array + 1)

おわりに

今回は、ポインタを入門してみました。配列のくだりはあまり理解しなくても問題ありませんが、 配列とポインタを頭の中で変換できるとポインタの理解が深まる気がします。 ポインタを理解するには、実際にコードを書くしかないと思います。 最低限以下を覚えておけば、ポインタで使われるテクニックはすべて理解可能だと思っています。

  • ポインタの宣言は、int * pointer のように行う。
  • 変数の保持されている場所のアドレスは、& で見ることができる。
  • ポインタの中には、アドレスを入れる。
  • ポインタの手前に * を付けると、アドレス先の中身を見に行く。

Re:ゼロから始めるポインタ入門 #0

仕事でC言語を使っていて、ポインタでたまに分からなくなる時があるので、整理するために書き起こすことにしました。

何回かに分けてポインタを復習していく予定です。
今回は、準備運動なのでポインタとあまり関係ありませんが、知っていると理解しやすいと思い、書きました。

一応断りを入れておきますが、中身の正確さは保証しません。
理解のきっかけにしてもらって、正確な情報は書籍などで入手してください。

環境

まず環境ですが、C言語を書けて実行できるなら何でも構いません。
自分は、

で行っています。

変数と型

知っていたら読み飛ばして大丈夫です。

変数

変数とは、不定値のことです。つまりその時々によって、値が変化するということです。 定数の逆ですね。プログラミング言語の中では、値を入れるための器のようなものです。 C言語だと以下のようにして、定義します。

int variable = 10;

これは、variable という変数に 10 という値を入れたという意味になります。 で、variable の手前にある int というのは、変数の型を決めるためのキーワードです。 int だと、整数の値を入れる専用の器を用意することになります。

他にも文字型や浮動小数点型があります。これらの違いは何かというと、「器の大きさ」と その中に入っている「値の表現の違い」を決めています。 まず、「器の大きさ」ですが、値を入れる場所を作るということは、その場所が必要になります。 その場所はもちろん有限です。いわゆるメモリがその場所になります。その中の一部を借ります。 で、今回の int はどれだけ借りるかというと、4Byte です。 bit で表すと 1Byte8bit なので、 32bit ですね。

文字型の char だと、1Byte です。int の中には 2 種類の型があり short intlong int があります。 short2Bytelong4Byte です。long intint は同じ大きさになります(環境によっては変わるかも)。 他にも型がありますが、気になる方は調べて下さい。

ここからは、正直ポインタと関係はあまりないので読み飛ばして大丈夫です。

次に表現の違いですが、変数の中に入っている値は、すべて 2 進数で表されています。 2 進数とは、0 と 1 で表現する数字です。2 の基数で表現するので 2 進数 なのですが、 あまり気にする必要はないでしょう。

で、先ほどの

int variable = 10;

ですが、10 はマシンから見れば、2 進数 で表すので、1010 です。 これを人でも理解しやすいように 10 進数 で扱えるようにしているに過ぎません。 それで、表現の違いについてですが、この値を型によって意味を変えているだけです。 何が言いたいかというと、中に入っている値は同じでも型によって意味が変わるということです。

では、まず以下のコードをビルドして実行してみましょう。

#include <stdio.h>

int main()
{
    int variable = 65;
    printf("variable: %d\n", variable);
    return 0;
}

実行すると variable: 10 と表示されると思います。
次に以下を実行して下さい。

#include <stdio.h>

int main()
{
    int variable = 65;
    printf("variable: %c\n", (char)variable);
    return 0;
}

結果は、どうでしょうか。 variable: A と表示されましたか?
つまり、 int 型の 65 というのは、char 型だと A になるのです。
以下のように意味を変えていると見た方いいかもしれません

【2進数から整数型】 0100 0001 → 65
【2進数から文字型】 0100 0001 → A

しっくり来なくても大丈夫です。ポインタとはあまり関係ありませんので。 ただ、知ってると面白いかなと思って書きました(面白くなかった? ごめんなさい……)。

おわりに

今回は以上です。 書き終わってから思いましたが、ポインタと関係あるのか微妙ですね。 ただ、2進数が分かっているといろいろ便利なので、消さずに残しておこうと思いました。 2進数の計算は、Widnows標準の電卓で設定をプログラマーに変えると計算できるので 正確に計算できる必要はないですが、2 進数の計算と 2 の乗数の 10 乗と 5 乗は覚えておくと便利です。

UE4 で http 通信を行う

少し前に UE4 で http 通信をしようと思い、ネットで方法を探していたのですが、 バージョンの違いか、手順が悪いのか、上手くいかず悩んだ末、UE4 の公式ドキュメントの方法で出来たので、その方法をまとめます。

以下、自己責任で行って下さい。

UE4.10 How To Make HTTP GET Request in C++ - Epic Wiki

上記のURLの方法をそのまま行えば出来ます。

ただ、php 周りの説明が分かっている前提なので、その辺補足出来たらいいなと思い、この記事を書くことにしました。

環境

  • Windows 10
  • UE4.14.3
  • VisualStudio 2015
  • XAMPP 3.2.2

プロジェクトの作成

まず、新規プロジェクトでC++のタブを選択します。 そして、基本コード(BASIC CODE)を選択します。

f:id:pickles-ochazuke:20170213214210p:plain

すると、VisualStudio が立ち上がると思います。気長に全ファイルを読み込むのを待ちます。
読み込めました? では、ビルドしましょう。
とくに問題が起こらないとは思うので、次に進みます。

アクタの作成

UE4 のエディタで http を取得するアクタを作ります。
まず、コンテンツブラウザの新規追加を選び、新規 C++ファイル… を選択します。親クラスは、Actorを選択します。
ファイル名は何でもいいです。今回は、GetHttpActorとしました。あと、パブリック、プライベートは特に選択しませんでした。
クラスを作成をクリックして、リコンパイルが終わるのを待ちます。

ソースコードの編集

では、プロジェクトの中身をいじっていきます。

Build.cs

”プロジェクトファイル名”.Build.cs という名前のファイルが VisualStudio のソリューションエクスプローラーにあると思います。
今回、自分のプロジェクト名は、MyProject(つまりデフォルトの名前)にしたので、MyProject.Build.cs というファイルがあるはずです……ありました。

f:id:pickles-ochazuke:20170213220228p:plain

見つかりましたか? よく探してくださいね。ソリューションエクスプローラーの検索を利用するといいかもしれません。例えば、.Build.cs で検索してみましょう。Games のフォルダ内を探して下さい。もう見つかった? お疲れ様です。では、次に行きましょう。

先ほど見つけたファイル(画像だと MyProject.Build.cs)を開いてください。

MyProject.Build.cs

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore"});

"Http", "Json", "JsonUtilities" という一文があると思います。バージョンによっては違うかも……。 PublicDependencyModuleNames.AddRange を探すといいかもしれません。見つけたら、{}内に以下を追加します。
すると以下のようになると思います。

MyProject.Build.cs

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Http", "Json", "JsonUtilities" });

このファイルはこれで以上です。

Engine.ini

次は、Engine.ini ファイルを探します。VisualStudio は使いません。そこには表示されないからです。 プロジェクトフォルダが保存されている場所に移動してください。そして、今回のプロジェクト名のフォルダの中に移動します。Saved/Config/Windows と移動して下さい。もしかしたら Windows がないかもしれません。Config 以下まで移動したら、Engine.ini を探して下さい。自分は、MyProject/Saved/Config/Windows の下に Engine.ini がありました。そして、てきとうなテキストエディタで開きます。

そして、一番下に以下を追加します。

Engine.ini

[HTTP]
HttpTimeout=300
HttpConnectionTimeout=-1
HttpReceiveTimeout=-1
HttpSendTimeout=-1
HttpMaxConnectionsPerServer=16
bEnableHttp=true
bUseNullHttp=false
HttpDelayTime=0

追加したら、保存して閉じて下さい。またVisualStudio に戻ります。

GetHttpActor.h

http を取得するアクタを作ったと思います。そのヘッダファイルを開きます。
今回だと、GetHttpActor.h です。 まず、以下のようにインクルードファイルを追加します。

GetHttpActor.h

#include "Runtime/Online/HTTP/Public/Http.h"

public: 以下に次の内容を追加します。

FHttpModule* Http;

/* The actual HTTP call */
UFUNCTION()
void MyHttpCall();
 
/*Assign this function to call when the GET request processes sucessfully*/
void OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);

ヘッダファイルは以上です。

GetHttpActor.cpp

次は、ソースファイル GetHttpActor.cpp をいじります。まず、コンストラクタ AGetHttpActor() に以下を追加します。

Http = &FHttpModule::Get();

そして BeginPlay() に以下を追加します。

MyHttpCall();

以下のメンバメソッドを追加します。

GetHttpActor.cpp

/*Http call*/
void AGetHttpActor::MyHttpCall()
{
TSharedRef<IHttpRequest> Request = Http->CreateRequest();
Request->OnProcessRequestComplete().BindUObject(this, &AGetHttpActor::OnResponseReceived);
//This is the url on which to process the request
Request->SetURL("http://localhost:8081/WebApi/getint.php");
Request->SetVerb("GET");
Request->SetHeader(TEXT("User-Agent"), "X-UnrealEngine-Agent");
Request->SetHeader("Content-Type", TEXT("application/json"));
Request->ProcessRequest();
}

/*Assigned function on successfull http call*/
void AGetHttpActor::OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{

 //Create a pointer to hold the json serialized data
 TSharedPtr<FJsonObject> JsonObject;

 //Create a reader pointer to read the json data
 TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());

 //Deserialize the json data given Reader and the actual object to deserialize
 if (FJsonSerializer::Deserialize(Reader, JsonObject))
 {
 //Get the value of the json object by field name
 int32 recievedInt = JsonObject->GetIntegerField("customInt");

 //Output it to the engine
 GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, FString::FromInt(recievedInt));
 }
}

ひとまずは、コピペで構いません。
お疲れ様です。C++ に追加することは以上で終了です。
ビルドが通るか確認しましょう。

これで、GetHttpActor をレベル上に置けば http を取得してくれるのですが、今の状態で行っても http は取得できません。http を発行してくれるサーバがないからですね。では、サーバの準備をしましょう。

XAMPP

サーバを立てる方法はいろいろありますが、今回は XAMPP を使います。 インストールの方法は、ネット上にたくさんあるので、そちらにお任せします。 例えばこれを見るといいでしょう。

XAMPP を立てるときにセキュリティが気になる人は、セキュリティの設定を行うか、ネット回線を切ってしまいましょう。

たぶん XAMPP を使って Apache を立てるとエラーが発生すると思います。 その場合、以下の記事を見ると解決するかもしれません。

余裕があれば、別記事にまとめたいと思います……。

PHP ファイルの作成

XAMPP を上手く入れることが出来ましたでしょうか? お疲れ様です。あと少しで完了です。では、XAMPP を無事インストールしたので、PHP のファイルを作ります。

以下の内容をコピペして下さい。

getint.php

<?php
    //Create a variable to be used in 
    $theVar = array('customInt' => 5);
 
    //Set the headers
    header('Content-Type: application/json');
 
    //Encode the variable, and save the encoded string
    $encoded = json_encode($theVar);
 
    //Output it
    echo $encoded;
?>

そして、getint.php というファイル名にして保存します。 このファイルを以下に置いて下さい。

C:\xampp\htdocs\WebApi

WebApi フォルダは作る必要があると思います。XAMPP をインストールするときに、保存場所を変更した場合は、 C:\ の下にないかもしれません。getint.php ファイルを置くことが出来たら、少しだけ C++ ファイルをいじります(Apache のポート番号を変えていなかったら必要ないかも)。

C++ 側の URL を編集

GetHttpActor.cpp を開いて下さい。 そして、void AGetHttpActor::MyHttpCall() の中を見ます。

Request->SetURL("http://localhost:8081/WebApi/getint.php");

という一文があると思いますが、この SetURL の中身を変えます。 見ると分かるかもしれませんが、中身は URL を表しています。 注意してほしいのは、 localhost:8081 の 8081 です。Apache のポート番号とここのポート番号が合っていないと、正しく処理することが出来ません(URLの場所が見つからないからです)。

サーバを立てる

SetURL の中身を書き換えたら、XAMPP の Apache の Start のボタンをクリックして下さい。すると Apache の文字の周りが黄緑色みたいになると思います。黄色や赤色だと何か問題が発生していると思います。エラーの内容をコピペして検索してみましょう。

問題がない場合、サーバを立てることに成功しています。実際に確認してみましょう。ブラウザを開いて、以下のように入力します。

例えば、http://localhost:94/ とします(ポート番号は人によって異なります)。すると以下のような画面が表示されます。

f:id:pickles-ochazuke:20170214230230p:plain

SetURL と同じURLを指定してみましょう

http://localhost:94/WebApi/getint.php

すると以下のような文章が出ると思います。

{"customInt":5}

これが出ていれば成功です。
では、VisualStudio の方でビルドをします。成功したら、UE4 エディタに戻り、GetHttpActor を選択します。右クリックをして、「GetHttpActor に基づくブループリントクラスを作成します。」 を選択します。そして、てきとうなファイル名(自分は、MyGetHttpActor にしました)を設定し、てきとうな場所に作って下さい。そして、 MyGetHttpActor を開きます。開いたら、コンポーネントを追加で視覚的に置いてあることが分かるようなものを追加しましょう。自分はキューブを追加しました。そしてコンパイルをして、レベル上に配置します。

確認

最後に確認です。

  • XAMPP は正常に動作していますか?
  • Apache は正常に動作していますか?
  • ブラウザを開いて、http://localhost:94/WebApi/getint.php にアクセスすると、php のコードが正しく動いていますか? PHP のコードをコピペしていたら {“customInt”:5} のように表示されるはずです。
  • VisualStudio は正しくビルド出来ていますか?
  • SetURL の中身は http://localhost:94/WebApi/getint.php になっていますか?
  • UE4 のレベル上に GetHttpActor を継承したブループリントクラスのインスタンスが置かれていますか?

では、UE4 エディタのプレイをクリックしましょう。
以下の画像のように文字が表示されるはずです。

f:id:pickles-ochazuke:20170214231918p:plain

無事、http 通信をすることが出来ました。とても小さなことですが、これだけでもいろいろ幅が広がります。長くなりましたが、以上です。 お疲れさまでした。

おわりに

http 周りのソースコード調べないとなぁ……。
あと、分かりづらいところがあればコメントを下さい。