としおの読書生活

田舎に住む社会人の読書記録を綴ります。 主に小説や新書の内容紹介と感想を書きます。 読書の他にもワイン、紅茶、パソコン関係などの趣味を詰め込んだブログにしたいです。

2021年03月

3753817_s


Qiitaでカフェでプログラミングしてる風(でも何もやってない)Java(クソ)コードという記事を読んで、自分でも作りたくなりC++で実装してみました。

本記事では元の思想とは少し違いますが、Windowで動くプログラミングしている風コードを作成していきます。

Windowsでもカフェで素敵なエンジニアだと思われたい(笑)




ステータスが変化してる風コード


まずは何かしらの処理が動いている風に見えるコードです。

/**
 * ステータスを更新してる風コード
 */

#include <iostream>
#include <random>
#include <windows.h>

using namespace std;

int main(void){
    // 50文字まで#を表示する
    int x = 50;
    // カウントアップする変数
    int y = 0;
    // 乱数生成の準備
    std::random_device rnd;
    std::mt19937 mt(rnd());
    std::uniform_int_distribution<> rand10(09);
    while(true){
        if (x != y){
            // 上限まで#をたしていく
            cout << "#";
        }
        else{
            // 50文字になったら「done!! + 改行」を出力し
            // 何かが終わった感を演出
            cout << " done!!" << endl;
            y = -1;
        }
        // カウントアップしていく
        y++;
        // 高速で出力すると素敵感が出ないので
        // 出力待ち時間を作成する
        int sleepTime = 10;
        // ランダム値にマッチすると待ち時間をさらに長くする。
        // 何か大きな処理をしているように見えること請け合い
        int osooso = rand10(mt);
        if ((4 < osooso) && (osooso <= 6)){
            sleepTime = 100;
        }
        // 待つ
        Sleep(sleepTime);
    }
    return 0;
}


DustStatus




コンパイルが動いている風コード


こちらは乱数を使って何かを自動で動かしている風のコードです。

/**
 * 数字の羅列を出力し、何かを自動で作ってる風コード
 */

#include <iostream>
#include <string>
#include <random>
#include <windows.h>

using namespace std;

int main(void){
    // 乱数生成の準備
    std::random_device rnd;
    std::mt19937 mt(rnd());
    std::uniform_int_distribution<> rand10(09);
    while(true){
        // カウントアップ
        int x = 1;
        // 出力文字列
        string code = "";
        while (true)
        {
            // 0から9までの数値をランダムで出力
            int num = rand10(mt);
            // 出力文字列に足していく
            code += to_string(num);
            if (x == 50) {
                // 50文字でブレイク
                break;
            }
        x++;
        }
        // 数値の羅列を出力:いい感じにコンパイルしてる感が出る
        cout << code << endl;
        // 高速で出力すると素敵感が出ないので
        // 出力待ち時間を作成する
        int random = rand10(mt);
        int sleepTime = 100;
        // ランダム値にマッチすると待ち時間をさらに長くする。
        // 何か大きな処理をしているように見えること請け合い
        if (4 < random  && random <= 6) {
            sleepTime = 500;
        }
        // 待つ
        Sleep(sleepTime);
    }
    return 0;
}


DungCompiler


まとめ


こういった意味がないけどおもしろいコードを思いつく人ってすごいですね。

今回はJavaのコードをC++に置き換えただけになってしまいましたが、今度はオリジナルのカフェでプログラミングしてる風コードを作ってみたいです。





3753817_s

本記事ではVisual Studio Codeで利用できるコンパイラのMinGwでDLLを作成して、呼び出す方法までを紹介します。

DLLを作成するとか難しそうというイメージをもっている人もいるかもしれませんが、やってみると意外と簡単なのでこの機会に作り方を覚えてしまいましょう。



DLLを作成する


今回は、サンプルとして足し算と引き算を行う関数が実装されているDLLを作成します。

ソースコードは以下の通りです。


DLLのヘッダファイル


// Calc.h
#ifndef H_CALC
#define H_CALC

int addition(int xint y);     // x+yをする
int subtraction(int xint y);  // x-yをする

#endif // H_CALC


DLLのソースファイル


// Calc.cpp
#include "Calc.h"

int addition(int xint y){
    return x+y;
}

int subtraction(int xint y){
    return x-y;
}


オブジェクトファイルの作成(.o)


ソースコードを用意したところでMinGwのG++コマンドを使ってDLLを作成していきましょう。

先ほどのソースコードにもコメントで書いているのですが、ソースコード名はCalc.cppです。

まず最初に-cオプションを使ってオブジェクトファイルを作成します。コマンドは以下のとおりです。

g++ -c .\Calc.cpp

このコマンドを実行するとCalc.cppと同じディレクトリにCalc.oというファイルが作成されます。


DLLの作成


DLLは-sharedオプションを使用することで作成することができます。コマンドは以下のとおりです。

g++ .\Calc.o -o Calc.dll -shared

上記のコマンドを実行するとCalc.dllというファイルが作成されます。

DLLの作成は以上で終了になります。
たったこれだけでいいの問う感じですが、やってみるとむちゃくちゃ簡単なんですよね。



作成したDLLを使う


次に先ほど作成したCalc.dllを呼び出す方法を紹介していきます。


DLLの呼び出し元のソースコード


// main.cpp
#include <iostream>
#include "Calc.h"

int main(void){
    int xy;

    std::cin >> x >> y;
    std::cout << "addition:" << addition(xy<< std::endl;
    std::cout << "subtraction:" << subtraction(xy<< std::endl;
    return 0;
}


コンパイルする


ソースコードができたらコンパイルしていきましょう。

コンパイルのコマンドは呼び出し元のコードをコンパイルするときにDLLの名前を教えてあげるだけです。

g++ -o .\main.exe .\main.cpp .\Calc.dll


実行結果


.\main.exe
3 5
addition:8
subtraction:-2


コンパイルして作成したmain.exeを実行してみると、DLLの関数が呼び出されていることが分かりますね。



まとめ


今回は、MinGwでDLLを作成して、その後作成したDLLを使う方法を紹介しました。

今回はコマンドを全て手打ちで実行していきましたが、ソースコードが増えるとすごく面倒です。

なのでそいうときはmakeファイルを作成してみましょう。

makeファイルの作り方については後日紹介させていただきます。




3753817_s

本記事では、C言語からC++で作成したDLLを呼びだす方法の失敗例と成功例を紹介していきます。

結果だけが知りたいという人はC言語からC++のDLLを呼び出すの章を読むだけで大丈夫です。



C++のDLLが呼び出せない例


まず最初にCからC++のDLLの呼び出しが失敗する例を紹介します。


C++のDLLのコード


ヘッダファイル

#ifndef H_SAMPLE
#define H_SAMPLE

void PrintSample();

#endif // H_SAMPLE


ソースファイル

#include "sample.h"
#include <iostream>

void PrintSample(){
    std::cout << "Hello CPP!!" << std::endl;
}


C言語のコード


#include "sample.h"

int main(void){
    PrintSample();
    return 0;
}


上記のコードをコンパイルすると下記のエラーコードがでてコンパイルすることができません。

undefined reference to `PrintSample' collect2.exe: error: ld returned 1 exit status




C言語からC++のDLLを呼び出す


上記のコードからC++のDLLのヘッダファイルを修正するだけで、C言語からC++の関数を呼びだせるようになります。

修正内容はヘッダファイルにextern "C"を追加するだけです。

修正したコードを以下にのせます。DLLのヘッダファイル以外は先ほどの失敗例で紹介したものと同じです。

ヘッダファイル

#ifndef H_SAMPLE
#define H_SAMPLE

#ifdef __cplusplus
extern "C"{
#endif /* __cplusplus */

    extern void PrintSample();

#ifdef __cplusplus
#endif /* __cplusplus */
#endif // H_SAMPLE


ソースファイル

#include "sample.h"
#include <iostream>

void PrintSample(){
    std::cout << "Hello CPP!!" << std::endl;
}


C言語のコード


#include "sample.h"

int main(void){
    PrintSample();
    return 0;
}


実行結果


Hello CPP!!




まとめ


extern "C"をC++のDLLのヘッダファイルに追加するだけで、簡単にC言語からC++のDLLを利用することができました。

ちなみに今回作成したDLLはC++でもそのまま利用することができるので、C言語用とC++用でDLLを2つ作成するひつようもありません。



PXL_20210306_095514392.MP_1


住野よるさんの『麦本三歩の好きなもの 第二集』 を読みました。

一巻目読んだ時点でもう続編はでないのかなとかなんとなく思っていたので、発売を知ったときはむちゃくちゃ嬉しかったです。

以下、あらすじと感想になります。



『麦本三歩の好きなもの 第二集』のあらすじ


図書館勤務3年目に突入した、20代女子の麦本三歩。

3年目になっても相変わらず仕事ではミスが多く、すぐにぼんやりとする癖が抜けない。

しかし、そんな三歩にもとうとう後輩ができた。

だが、後輩は三歩とうってかわって、真面目でしっかりものの女子!!

三歩はそんな後輩を前に先輩としての威厳を守ることができるのか!?


後輩との出会い以外も、合コンで新たな出会いがあったりなど三歩の社会人三年目は新しいことだらけだ。

しかし、出会いがあれば別れもある…。

心温まる日常小説が再び始まる。



感想(ネタバレあり)


もう再び三歩と会えるっていうだけでも、嬉しいのに内容もとても良かったです。

第一作目では、三歩が社会人一年目ということと第一作目ということも相まって、三歩の初めての社会人生活や三歩の自己紹介的な作品が多くありました。

今回の第二集では、趣味に関する話などもあるのですが、前作と比べると新しい出会いや別れに関する作品が多かった印象です。

第二集のテーマは個人的には『出会いと別れ』だと思っていたりします。



私たちと一緒に成長していく麦本三歩


「麦本三歩は焼売が好き」の冒頭で三歩が社会人3年目とみてこれだけでテンションが上がってしまいました。

第一巻が発売されたのが2019年で第二集の発売日が2021年だから、三歩も私たちと同じで2歳成長しているのです!!

サザエさん方式の世界や時系列が遅い作品では、巻が進むにつれて登場人物との年齢差ができてしまい少し悲しい気分になるのですが、麦本三歩シリーズはそうではないみたいです。

個人的に同じだけ年齢をとる作品って『アフロ田中』シリーズぐらいしかしたなかったので嬉しい!

第一巻では、三歩が私と同年代の人物ということもあり、なかなか共感ができる内容も多かったので、今後もこの共感を味わえると考えると夜も眠れませんね(三歩は寝るのが好きだけど)

もし今後も第三集、第四集と発売されることがあれば三歩も一緒に成長していくことになりそうですね。



三歩の新しい出会い


三歩の先輩や友人も相変わらずいいキャラをしていたのですが、第二集人物もすごく良かったです。

中でも個人的に特に新しい要素だなと思ったのが、「麦本三歩は蟹が好き」の合コンで初登場したお兄さんです。

「麦本三歩は東京タワーが好き」では、お兄さんとのデートで今まで先輩や友人の前では見ることができなかった三歩の新しい顔を見ることができました。

男性キャラが少ないのもありますが、お兄さんといる三歩も新鮮でかわいかったです。

デートでのフリーメイソンの下りは個人的にかなりツボに入り一人でむちゃくちゃ笑ってしまいました。

他の物語でもお兄さんの名前が明示的にはでてきませんが、LINEで連絡を取り合ったり、再度デートの約束をしていたりかなり親しくしているのが分かります。

第三集でお兄さんと三歩がどのように発展するのかに注目ですね。

巻が進んで三歩とお兄さんが子育てする話などがあればかのり癒される気がします(笑)





先輩との別れ


第二集では、三歩にたくさんの出会いもありましたが、悲しい別れもありました。

それは、怖い先輩との別れです。

結婚し、妊娠したことで怖い先輩は図書館をやめることになりました。

社会人としてずっと働いていたら、同期も先輩も後輩もなんかしらの理由で会社を辞めていくことがありますが、3年目の三歩にとってはこれが初めてです。

私も三歩と同様にすごくお世話になった先輩が少し前に退職してしまったので、三歩の悲しむ気持ちが分かりすごく共感してしまいました。

怖い先輩が辞める前に三歩が一人でもやっていけるように認めるように一生懸命ミスをしないように働こうとしている様子は涙なしでは読むことができませんでした。

最後に怖い先輩に認めてもらえた三歩はとても嬉しくて、これからも頑張ろうと思えたんだろうな。

ただ、オチでタイトルの「麦本三歩は復讐ものが好き」を回収していて笑ってしまいました。今までの真面目なシーンはなんだったんだって感じでしたね(笑)


麦本三歩の日常シリーズって三歩が緩い感じだけど、まじめな内容もあってそのギャップが面白さを倍増させているんでしょうね。



第二集で一番好きな物語


第二集の全ての物語が面白かったのですが、個人的に一番を決めるとなると「麦本三歩は楽しい方が好き」がお気に入りです。

これほとんどの二十歳以上の方が共感できるよう内容なんでしょうけど、二日酔いになった日って三歩と同じように酒を止めると誓ってしまいますよね。

「もう、二度と酒いらない・・・。」
『麦本三歩の好きなもの 第二集』より

誓ったにもかかわらず数か月後には同じ失敗をしてしまうという…。

全人類から共感されてしまうような内容もあいまってこの話が一番好きです。



まとめ


第二集も三歩に癒されまくりました。

最近の日常小説では麦本三歩シリーズがナンバーワンの作品ですね。

第二集が出たばかりで気が早いですが第三集の発売が楽しみです。







3753817_s

静的メンバ変数を宣言した時に、コンパイルエラーが起きて
undefined reference to `Hogehoge::m_hogeNum'
といった感じに、宣言してたはずのメンバー変数が宣言していないとのエラーが発生しました。

本記事では、このエラーに対する対処方法をまとめていきます。




"undefined reference to"のエラーが出る場合のコード


以下のコードではをコンパイルすると冒頭で説明したように、「undefined reference to `Hogehoge::m_hogeNum'」というエラーメッセージが表示されます。


ソースコード

#include <iostream>

class Hogehoge{
public:
    Hogehoge(int num);
    ~Hogehoge();

private:
    static intm_hogeNum;
};

Hogehoge::Hogehoge(int num){
    m_hogeNum = &num;
}

Hogehoge::~Hogehoge(){}

int main(void){
    int x = 5;
    Hogehogehogehoge = new Hogehoge(5);

    return 0;
}



エラーメッセージ

undefined reference to `Hogehoge::m_hogeNum'
collect2.exe: error: ld returned 1 exit status



対策


調べてみると、staticメンバ変数も関数のように明示的にすることで"undefined reference"エラーを防ぐことができることが分かりました。

先ほど上記で紹介したコードを改造して、コンパイルがとおるようにしてみます。

#include <iostream>

class Hogehoge{
public:
    Hogehoge(int num);
    ~Hogehoge();

private:
    static intm_hogeNum;
};

int* Hogehoge::m_hogeNum = nullptr;

Hogehoge::Hogehoge(int num){
    m_hogeNum = &num;
}

Hogehoge::~Hogehoge(){}

int main(void){
    int x = 5;
    Hogehogehogehoge = new Hogehoge(5);

    return 0;
}

赤字にしている部分が先ほどのコードから追加した部分です。

intHogehoge::m_hogeNum = nullptr;

といった感じに明示的に宣言することで、"undefined reference"エラーを回避することができました。



まとめ


staticメンバ変数は、関数などとどうように明示的に定義しておく必要があることが分かりました。

久しぶりにC++を使ったりするとこういったくだらないミスで詰まってしまうことがありますので気をつけましょう。




↑このページのトップヘ