[Diary] 2022年もよろしくお願いします

自分がブログを始めたのが 2008/1/20 だったみたいで、当時はライブドアブログに書いてました

それから毎年1月を迎えるときに、「今年もよろしくブログ」を書いていましたが。。。
2019年で途絶えてしまいました…(T△T)

2022年の今年は書いておこうかなと!重い腰をあげてみました、ヨイショ!


予定管理

2021年の私的ハイライトといえば、バレットジャーナル を書き始めたことですね!
これは自作の手帳にバンバン書き込んでいくスタイルで、わたしには合っていました

習慣化

子供も居てるので、なかなか思うように時間が取れなくなり、物事を習慣化するようにしました

小さな習慣 という本を読んで、うまく習慣化ができるようになったので
このブログも、自分のための勉強も、習慣でぽちぽちとやっています

習慣でものごとをやると、いつの間にかできてる!という感激がありますね

(半面、期日の決まった目標達成には、習慣は不向きというのが判りました
 何事も経験してみるもんですね)

毎日、習慣化を意識的にやってるのは以下

すでに苦にならず毎日習慣化DONEのもの

意識して毎日必ずやるようにしたら、歯磨きのように無意識で読書は出来るようになりました

この調子で、他のものも完全な習慣にしたい。。。というのが今年の目標かな~

技術

あとは Visual Studio が 2022 になったのもあって、何か作りたいなーと思い、ゲーム屋さんらしくレンダリング(まずは DirectX12)の勉強を年末から開始しています
このブログにもなんかトピックが書けるようになったら良いかな~

あ!年末に C++ Advent Calendar 2021 に参加できたのは、かなり嬉しかったです
久しぶりにアドカレに参加できました!

2022年も、どうぞよろしくお願い致します!


[C++] Advent Calendarへの参加履歴 2010-2021

自分メモです

過去に参加した C++ Advent Calendar の自分の記事のリンク

C++ Advent Calendar jp 2010

Boost Advent Calendar 2011

C++ Advent Calendar jp 2012

C++ Advent Calendar 2013

C++ Advent Calendar 2021


意外と参加してました。。。

こうやって記録に残すのは、なんだか気分が良いですね


[C++] Modulesのコンパイル(MSVC ver)とBMIについて

この記事は C++ Advent Calendar 2021 1日目(初日!)の記事です。

少し前からC++に Modules がやってきました
C++20 対応のメジャーどころのコンパイラ(MSVC/gcc/Clang など)で使うことができます

個人的にはビックウェーブが来たーーーと思ってまして、つねづねポチポチと Modules について調べていました

それを少しまとめたいと思います

モジュールの説明

昔ながらのプリコンパイルヘッダの概念を、今風にした感じでしょうか

ヘッダファイルをインクルードしていたものを Modules に置き換えることが出来ます

ヘッダファイルだと、

インクルードの順番に気を付けたり
コンパイル時間が長くなったり
インクルードガード書いたりと
ゆーてローテク文字列だったのですが、

それがバイナリとして公式に提供されました

Modulesを記載するファイル

各コンパイラによって(推奨)拡張子が異なります

(参考)

以下、、MSVCで話を進めます
(コンパイラによって異なる所が多いので)

モジュールファイルについて

MSVC の場合、モジュールにしたいファイルは .ixx という拡張子を付けます
(Clangだと .cppm、GCCだと .cxx とかになります)

サンプルはこんな感じ

hello.ixx

1
2
3
4
5
6
// hello.ixx:
export module MyHello;

export int f() {
    return 42;
 }

利用する側はこんな感じで↓↓↓ import すれば使えます
(従来は #include "hello.h" とか書いていた場所です!)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// main.cpp 
#include <iostream>
#include <cstdlib>

import MyHello;  // モジュール使うよの宣言

int main() {
  auto a = f();

  std::cout << f();
}

サンプルだけ見ると、なんてことのないコードですね
メイン関数は #include してた箇所を inport に変更しただけです

モジュールをバイナリ化する

モジュールを記載する .ixx ファイルは、.ifc にプリコンパイルでバイナリ化されます

ややこしいのが、コンパイラによってこのあたりの呼び名が異なってて、こんな感じ

MSVC Clang
モジュールファイル名  → .ixx .cppm
モジュールファイルをプリコンパイルしたもの→ .ifc .pcm

ちなみに「モジュールファイルをプリコンパイルしたもの」を BMI と呼び、
Binary Module Interface の略になります

この BMI ファイルを各 cpp ファイルなどが import することになります

(参考)

VC++でのコンパイル方法

単純のため、まずはコマンドラインでやってみます

利用したVC++バージョンはこちら

コマンドは2つ

1
2
> cl /c /std:c++20 /EHsc hello.ixx
> cl /std:c++20 /EHsc /reference MyHello=MyHello.ifc main.cpp hello.obj

1つ目のコマンドでモジュールをプリコンパイルし、
2つ目のコマンドで obj をリンク、そして main.exe の出力をします

<1. モジュールのプリコンパイル>

C:\my\dev\sample_module01>cl /c /std:c++20 hello.ixx
Microsoft (R) C/C++ Optimizing Compiler Version 19.30.30705 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

hello.ixx

これで、hello.objMyHello.ifc が出来ました

(余談)cl.exe はモジュールのコンパイル時に同時に2つ(.obj.ifc)のファイルを出力してくれて楽です

Clang は別々のコマンドで出力するので、cl.exe とは少し作り方が異なっています
.pcm ( VC++で言うところの .ifc) を出力した後、それを元に .o ( VC++の .obj) を出力します
このあたりはまだ次回に投稿したいです

<2. 実行ファイル生成>

C:\my\dev\sample_module01>cl /std:c++20 /EHsc /reference MyHello=MyHello.ifc main.cpp hello.obj
Microsoft (R) C/C++ Optimizing Compiler Version 19.30.30705 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
Microsoft (R) Incremental Linker Version 14.30.30705.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe
main.obj
hello.obj

main.exe が出来ました

実行してみます

C:\my\dev\sample_module01>main.exe
42

問題なし(^^♪

(備考)コンパイルオプションの注意点

VC++のコマンドラインオプションが

これらの間で一致していないとき、ワーニングが出ました(C5050

main.cpp(7): warning C5050: Possible incompatible environment while importing module ‘MyHello’: _CPPUNWIND is defined in current command line and not in module command line

そのため今回、hello.ixx 内では <iostream> は利用していないのですが、/EHsc オプションを付けています

(参考)

BMIってなによ?

プリコンパイルされた Binary Module Interface って何なのでしょうか?
この中身は一体?

さんざん調べましたが、大した情報が載ってないですね。。。

これ、BMIというのは Modules を扱うための概念のようです

これはコンパイルの過程のものなので、各コンパイラベンダーが作る箇所であり、明確に公開情報として詳細が提示されているわけではなさそうです
現時点では概念がちらほらと記載されているだけのようでした

実際に、プリコンパイルで作られた .ifc.pcm の中身は

がひとまとめにされてるようです

という記述を見つけましたが、出展元が判らなくなったので、思い出したら追記します。。。

(2021/12/4追記)
CppCon2019の資料が参考になりました!
Practical Cpp Modules - CppCon 2019
https://github.com/CppCon/CppCon2019/blob/master/Presentations/practical_cpp_modules/practical_cpp_modulesboris_kolpackovcppcon_2019.pdf

もちろん、コンパイラによって、さらにバージョンによっても形式は様々なんでしょう

モジュールの配布ってどうやるの?

モジュールのバイナリを配布することはできないです
共有する場合はあくまでソースコードと共に配布になります

また、作られた BMI、つまり .ifc.pcm ファイルは不変的なバイナリではないみたいです

ライブラリのように配布はできないのですね。。。

(余談)Modules の提案を推し進めている Gabriel Dos Reisさん は、Common Module Interface Format を作りたいみたいですが…
具体的に今の段階では、配布目的のものは出ていないようです

(参考)

所感

まだ2021年12月の時点では、Modules 機能が完全に動作するコンパイラもないみたいですし
そもそも各コンパイラによって記載方法や推奨が異なるので、なんとも道半ばな印象はあります

Modules を利用するための手順やお作法も多く、また情報も限られているので、取り組みにくいですね

マイクロソフトの VC++チームブログ は、コンパイラベンダーとして結構 Moduleds の具体的な情報を出しているように感じました
(Clangももうちょっと頑張って。。。あとGCC。。。おまえはやる気あるのか。。。)

Modules に関して取り組まれている人たちの歴史はとても長く
かつ現在のヘッダファイルがベストだとは思えないので
個人的に一押ししたい機能だと改めて思いました

所感その2

C++ Advent Calendar!

ずいぶん昔に一度だけ参加したことがあったのですが、それからなーんにもしてませんでした

今回、意を決して投稿できて良かったです

かなりよく調べたつもりですけど、間違いなどあったら気軽に @hr_sao まで教えていただけると嬉しいです

C++楽しい~♪


[C++]Compiler Explorerの出力結果の表示方法

Compiler Explorer というオンラインコンパイルサービスがあります

書いたC++コードのアセンブリ出力結果をリナルタイムに表示してくれるサービスです

すごーーー👀
初めてこのサービスを見た時には感激しました〜

さておき、
わたし、これで実行結果を見る方法を知らなかったんですね…ハズカシー(*ノдノ)

「Output」を押すと出力結果ウィンドウは出てきますが
このリターン値だけじゃなくて、 std::cout の結果も欲しいんですけど…👀

ちょっと調べてみたらすぐに判明しました><。

Outputの設定項目に Execute the code のチェックボックスがあるので、それを選択すれば表示されます

出力はこんな感じですね〜

便利です〜


[macOS] BootCampの起動OSを選ぶ

macOS に BootCamp を入れると、デフォルト起動OSが Windows になります
(わたしの環境ではそうなりました)

これ、デフォルトを macOS に戻すには、

システム環境設定
 > 起動ディスク

ここを macOS にすればOK

Windows を立ち上げたい時には、
電源を入れた直後に option を長押しすれば、起動OS選択画面になります


[Windows] そのexeがx64かx86かを見分ける方法 Part2

先日、こんなブログを書きました

このブログを公開したところ、Twitterで @ripjyr さんより
macなら file コマンドあるよと教えていただいたので追加記事を書いておきます~

上記のブログ記事では、 exe データが 32bit なのか 64bit なのかを調べるやりかたとして
3つのチェック方法を記載しました

今回は4つ目の方法の紹介です~!

パターン4. file コマンドで調べる(macOSの場合)

これは mac のみの環境で、Win exe を調べたいって時のお話です

mac には file コマンドがあって、それを使うと簡単に Windows exe のビット(PEヘッダ)を調べることができます

$ file 調べたいファイル名 

PE32 executable (GUI) Intel 80386, for MS Windows と表示されます!

1
2
$ file AGDRec.exe  
AGDRec.exe: PE32 executable (GUI) Intel 80386, for MS Windows

PE32+ executable (GUI) x86-64, for MS Windows とでます

1
2
$ file AGDRec64.exe
AGDRec64.exe: PE32+ executable (GUI) x86-64, for MS Windows

真に、素の mac でバイナリデータを見たいときは、これが良いですぅ!!!

謝辞

@ripjyr さん、教えてくださってありがとうございました ^^


[Windows] そのexeがx64かx86かを見分ける方法

手元にあるexeが64bitなのか32bitなのかを知りたい…

開発してるとこういう時がたまにあると思う…

多分ちょっとニッチな需要だけど、検索したらちゃんと誰かが既に調べてくれていました!

パターン1. Windows のメモ帳(notepad.exe)を使って調べる

何にもない環境でも、OS が Windows なら必ず入っているメモ帳”φ(・ェ・o)~メモメモ

これで調べるのが一番簡単な調査方法だと思います~

  1. メモ帳:notepad.exe で調べたい exe ファイルを開く

  2. 文字列 PE を検索する
    こんな感じ↓↓↓

  3. PE の後ろに空白がちょっとだけあり、その後に続く文字で判別できます

ふむふむなるほど!

パターン2. バイナリエディタを使って調べる

最近のバイナリエディターのおススメは hexdump for VSCode です
昔は TEXBIN を使ってましたが、VSCode 内で完結するのが良いですね~

  1. VSCode を開く

  2. 調べたい exe をドラッグ&ドロップする

  3. こんなメッセージが出る…(だが気にしない)

    1
    2
    
    The file is not displayed in the editor becouse it is either binary or users an unsupported eext encoding.
    Do you want to open it anyway?
  4. 右上に出てる Show Hexdump をポチッ!

  5. バイナリモードで見て、0x0100 前後(ファイルによる)の番地あたりに
    0x5045 (つまり PE )から始まる文字列があるので探す

  6. こんな感じ

ふむふむ、この方法も良い感じです(・ω・)ノ

パターン3. hexdump コマンドで調べる(macOSの場合)

mac しか持ってない環境で VSCode も入ってなくて Windows の exe のビットを調べたい時って一体…!?
とは思いますが(><)
先日、わたし自身が必要だったので、これも調べてしまいました

VSCodeがあればパターン2 の方法で調べられるのですが
mac の標準環境だけで調査したいときは、hexdump が標準で装備されているので
それを使うのも手です(。・_・。)ノ

# [-n バイト数] で先頭からのバイト数の分だけ表示出来る
$hexdump -n 400 バイナリを調べたいファイル名

上記の例だと、x86 のようですね
良い感じです

素の mac でバイナリデータを見たいときは、これが良いかも
パターン4がありました(追記)

パターン4. file コマンドで調べる(macOSの場合)

後日、こちらに追記しました

備考

いくつか他の exe のバイナリデータを見てみました

だいたいファイルの先頭の 0x0080 ~ 0x0140 くらいまでに PEヘッダがあるようです

参考


[C++] 実行環境の差異によるintワーニングが出ない書き方

C++のワーニングを放置していたのですが、そっと @srz_zumix さんが教えてくれてました

忘れないうちに”φ(・ェ・o)~メモメモ


x86環境とx64環境が混在してる場合にエラーが出やすい

こんなやつとか出ます…

1
2
3
4
5
6
// Warning が出る例
std::vector<int> my_vec = { 0, 42 };
uint32_t max_loop_counter = my_vec.size();  // ←ここね
uint32_t counter = 0;

// 以下、counter を max_loop_counter までなんらかの処理

これは x86環境だと warning は出ないのですが x64 環境想定でコンパイルすると、ワーニングが出ます

(Clangの例)
warning: Implicit conversion loses integer precision: ‘std::__1::vector >::size_type’ (aka ‘unsigned long’) to ‘u_int32_t’ (aka ‘unsigned int’) [-Wshorten-64-to-32]

( ̄□ ̄;
ええ、ええ、判っていますとも…
int 型が処理系によって異なるのは…

そこで、やっつけで修正するならこれ

1
2
// ベタにワーニングを取ろうとするとこんな感じ
uint32_t max_loop_counter = static_cast<uint32_t>(my_vec.size());

なのですが、もっとスマートは方法があります

1
2
3
4
// 今っぽい感じに
std::vector<int> my_vec = { 0, 42 };
auto max_loop_counter = my_vec.size();
decltype(max_loop_counter) counter = 0;

エレガントになりました…!素晴らしい(^^♪

警告のコンパイラー対応表がある

@srz_zumix さんが最近始められたプロジェクトらしいです

ワーニング対応表欲しいな…と思っていたところなので、結構良いかもしれない…

そして今日もC++修練は続く…


[Github] Github Actionsでブログを更新するようにしました

元々、このブログは hugo で作った静的HTMLを wercker でオートデプロイして作っていました
だけど wercker は設定の変更が多くてすぐにデプロイ出来なくなっていたんですよね~で、辞めました
これを作った当時は wercker がイケイケドンドンだったので
CircleCI から乗り換える人も多かったのですが
今となってはカジュアルデプロイは CircleCI …いやいや Github Actions があるやないか!
ということで、 Github Actions でデプロイするようにしてみました

Github Actions の設定ON

ここをポチっと押すと、Actionsの設定画面へ

Github Actions の設定ファイルを書いてみる

知識なしで初めてみましたが、すんなり簡単にビルド&デプロイすることが出来ました

というのも、GitHub Actions for GitHub Pages というデプロイするためのオールインワンアクションを公開してくれている方がいらっしゃいました
設定ファイルをまんま真似するだけで使えます

そしてこの方、hugo 対応のアクションも公開して下さっています!

ここの例に書いてる yaml ファイルのまんまで良い感じにデプロイ出来ました

こんな感じ↓↓↓

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# This is a basic workflow to help you get started with Actions

name: Deploy Github Pages to Hugo

# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
  push:
    branches: [ master ]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2
      
      - name: Hugo setup
        uses: peaceiris/actions-hugo@v2
        with:
          # The Hugo version to download (if necessary) and use. Example: 0.58.2
          hugo-version: 0.54.0 
          # Download (if necessary) and use Hugo extended version. Example: true
          # extended: true 

      # Runs a single command using the runners shell
      - name: Build Hugo
        run: hugo -v

      # Runs a set of commands using the runners shell
      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./public

超カンタンでした(。・_・。)ノ

CNAME 対応

Github Pages でカスタムドメインを使う際には
Github Pages の公開ブランチ(わたしの場合 gh-pages )のルートにドメイン名を記載した CNAME ファイルを設置する必要があるのですが
これが peaceiris/actions-gh-pages を使ってデプロイした際に、消えてしまってました

アクションの方の設定で対応することも出来たようなのですが
わたしはHugoそのものの設定を変えて、対応しました

Hugo の変換元のディレクトリに static/CNAME を設置するだけです
これも超カンタン

感想

SSHキーの外部登録などもしなくて良いし、Github の中で閉じてビルド&デプロイ出来るのが良いですね!

コネコネしたいときは CircleCI とか使うかもなぁと思いつつ、Github へのアクションメインの自動化であれば、これで充分ですね
今後も使っていくと思います~

参考


[c++] 2次元配列的な書き方

自分メモ

2次元配列

C++11 以前では、2次元配列はこんな感じで書いていました

1
2
3
4
5
6
// 2-dimensional array (raw type)
constexpr static float xy_raw[][2] = {
      { 0.f,  10.f}  // 0
    , { 20.f, 30.f}  // 1
    , { 40.f, 50.f}  // 2
};

これでも悪くは無いのですが、生配列を扱うと範囲外アクセスに気が付かない可能性が出てきます そこで C++11 から境界チェックが出来る配列の std::array が登場しました
これを使えば、C-styleの配列のノリで扱うことが可能です

さらに2次元配列にしたければ std::arraystd::vector に入れることで実現可能です

1
2
3
4
5
6
// 2-dimensional array (using stl)
const std::vector<std::array<float, 2>> xy_array = {
      { 0.f,  10.f}  // 0
    , { 20.f, 30.f}  // 1
    , { 40.f, 50.f}  // 2
};

悪くなさそう

動作確認

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <vector>
#include <array>

int main() {
  // ---------------------------------
  // 2-dimensional array (raw type)
  constexpr static float xy_raw[][2] = {
        { 0.f,  10.f}  // 0
      , { 20.f, 30.f}  // 1
      , { 40.f, 50.f}  // 2
  };

  std::cout << "xy_raw[0][1]: " << xy_raw[0][1] <<  "\n"; // 10

  // xy_raw[1][2] は out of rangeだけど warningになってる
  // これはたまたま xy_raw[2][0] と同じなので動作しているだけ
  std::cout << "xy_raw[1][2]: " << xy_raw[1][2] <<  "\n"; // 40

  // ---------------------------------
  // 2-dimensional array (using stl)
  const std::vector<std::array<float, 2>> xy_array = {
        { 0.f,  10.f}  // 0
      , { 20.f, 30.f}  // 1
      , { 40.f, 50.f}  // 2
  };

  std::cout << "xy_array[2][0]: " << xy_array.at(2).at(0) <<  "\n";  //40  

  // compile error
  //std::cout << "xy_array[1][2]: " << xy_array.at(1).at(2) <<  "\n";  // out of range accsess
}

結果

xy_raw[0][1]: 10
xy_raw[1][2]: 40
xy_array[2][0]: 40

コンパイル時に教えてくれるので助かります

参考