C++をWindows コマンドプロンプトでコンパイル

普段自宅ではMACBOOKで作業をしていますが、出張ででかけているときはWindowsを使っています。AOJでC++の問題を解くのに、Visual StudioのIDEをひらいてやってたこともあるのですが、プロジェクトを作って大掛かりになってしまうので、簡単にコマンドプロンプト(cmd)でやる方法をまとめます。

まず、コマンドプロンプトでコンパイルする場合はcl.exeを使います。これを直接実行すると、インクルードパスが設定されていません。と表示され実行っできません。

>cl main.cpp

Microsoft(R) C/C++ Optimizing Compiler Version 19.16.27030.1 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.
main.cpp
main.cpp(2): fatal error C1034: iostream: インクルード パスが設定されていません。

通常はスタートメニューから、「開発者コマンド プロンプト for VS 2017」を起動し実行します。 しかし、ディレクトリーに移動するのが非常に面倒です。

「開発者コマンド プロンプト for VS 2017」をプロパティで確認すると、

%comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat"

コマンドプロンプトでフォルダを指定して開く簡単な方法は、エクスプローラのアドレスバーにcmdと入力することです。そこで、上記で確認したコマンドを入力すると、コマンドプロンプトがコンパイル実行可能状態になります。

C:\Users\username\Documents\C\projects\helloworld>%comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat"
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.9.11
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************

cl.exeでは/EHscオプションをつけて実行します。

C:\Users\username\Documents\C\projects\helloworld>cl /EHsc main.cpp
Microsoft(R) C/C++ Optimizing Compiler Version 19.16.27030.1 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.
main.cpp
Microsoft (R) Incremental Linker Version 14.16.27030.1
Copyright (C) Microsoft Corporation.  All rights reserved.
/out:main.exe
main.obj

プログラム実行は、exeファイルを入力するだけ。今回はmain.exeができあがったので下記のようになります。

C:\Users\username\Documents\C\projects\helloworld>main.exe
Hello C++ World

Visual studio codeでターミナルでやるだけなら上記のやりかたで問題ありません。もしTaskで実行する場合は、実行毎に新規ターミナルが起動するのでできません。その場合は、Visual studio codeを一度閉じて、コマンドプロンプトで%comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat"を実行してからcode .と入力すると、Taskも実行できるようになります。フォルダも選択した状態で起動するので非常に便利です。

Qtではじめてのアプリをつくった。

最近はAizu Online Judgeでアルゴリズムの問題はやってましたが、 Qtの使い方の勉強で成果物が全然作ることができず、ブログの更新も全然できませんでした。C++やQtの初歩的なレベルのことは一通りやったので、このへんでなにか作ってみようと思い、Qtでアプリを作りました。

アプリといったも全く大したこともなく役に立つものではありませんが、自分の理解力を高めるためにアップします。

QLineEditで入力した数値をビットフィールドで作ったBits構造体にポインタで渡して、各ボタンのランプが点灯するようにしました。また、各ボタンを押したときには、Bits構造体を反転させるようにしています。

Bits構造体は下記の通り。

struct Bits
{
    int bit0:1;
    int bit1:1;
    int bit2:1;
    int bit3:1;
    int bit4:1;
    int bit5:1;
    int bit6:1;
    int bit7:1;
    int bit8:1;
    int bit9:1;
    int bit10:1;
    int bit11:1;
    int bit12:1;
    int bit13:1;
    int bit14:1;
    int bit15:1;
};

ポインタをキャストしてデータを参照しています。

Bits* bits; // Bits オブジェクト
int data; // 入力データ

data = ui->lineEdit_code->text().toInt();
bits = reinterpret_cast<struct Bits *>(&data);

ボタンを押したときに、 bitを反転させます。ポインタで参照すしているのでbitsを変更すればdataの値も変わります。ボタンをおしたら、QLineEditとボタンに表示します。

void MainWindow::on_pushButton_b0_clicked()
{
    bits->bit0 = ~bits->bit0;
    setLineData();
    displayButtons();
}

https://github.com/lingmujianshi/QBitDisplay

4×4行列の掛け算のプログラム

Aizu Online Judge でC++の問題で行列の掛け算の問題があり、その時はforループを3重に使って解きました。最近、OpenGL入門という本でOpenGLの勉強をしていて、サンプルに4×4行列の掛け算をするプログラムがありました。

for (int i = 0; i < 16; ++i) {
    const int j(i & 3), k(i & ~3);
    t[i] =
       a[ 0 + j] * b[k + 0] +
       a[ 4 + j] * b[k + 1] +
       a[ 8 + j] * b[k + 2] +
       a[12 + j] * b[k + 3];
}

4×4固定なので16個の配列を使います。驚いたのはiに対して3と~3のANDした結果を足して計算していること。ぱっと見てどうなっているか理解できなかったので、プログラムで一つずつ出力してみました。

まずは 3 と ~3を2進数で出力すると下記のようになります。

 3 : 00000000000000000000000000000011
~3 : 11111111111111111111111111111100

これをループで0 ~ 15を出力すると、& 3は

 0 &  3 = 0
 1 &  3 = 1
 2 &  3 = 2
 3 &  3 = 3
 4 &  3 = 0
 5 &  3 = 1
 6 &  3 = 2
 7 &  3 = 3
 8 &  3 = 0
 9 &  3 = 1
10 &  3 = 2
11 &  3 = 3
12 &  3 = 0
13 &  3 = 1
14 &  3 = 2
15 &  3 = 3

& ~3は

 0 & ~3 = 0
 1 & ~3 = 0
 2 & ~3 = 0
 3 & ~3 = 0
 4 & ~3 = 4
 5 & ~3 = 4
 6 & ~3 = 4
 7 & ~3 = 4
 8 & ~3 = 8
 9 & ~3 = 8
10 & ~3 = 8
11 & ~3 = 8
12 & ~3 = 12
13 & ~3 = 12
14 & ~3 = 12
15 & ~3 = 12

となります。0〜15は配列の下記のように割り当てます。

 0  1  2  3 
 4  5  6  7 
 8  9 10 11 
12 13 14 15

行列の掛け算は横✕縦でかけていきますので、式を出力するとこのようになります。

C[ 0]=A[ 0]*B[ 0]+A[ 4]*B[ 1]+A[ 8]*B[ 2]+A[12]*B[ 3]
C[ 1]=A[ 1]*B[ 0]+A[ 5]*B[ 1]+A[ 9]*B[ 2]+A[13]*B[ 3]
C[ 2]=A[ 2]*B[ 0]+A[ 6]*B[ 1]+A[10]*B[ 2]+A[14]*B[ 3]
C[ 3]=A[ 3]*B[ 0]+A[ 7]*B[ 1]+A[11]*B[ 2]+A[15]*B[ 3]
C[ 4]=A[ 0]*B[ 4]+A[ 4]*B[ 5]+A[ 8]*B[ 6]+A[12]*B[ 7]
C[ 5]=A[ 1]*B[ 4]+A[ 5]*B[ 5]+A[ 9]*B[ 6]+A[13]*B[ 7]
C[ 6]=A[ 2]*B[ 4]+A[ 6]*B[ 5]+A[10]*B[ 6]+A[14]*B[ 7]
C[ 7]=A[ 3]*B[ 4]+A[ 7]*B[ 5]+A[11]*B[ 6]+A[15]*B[ 7]
C[ 8]=A[ 0]*B[ 8]+A[ 4]*B[ 9]+A[ 8]*B[10]+A[12]*B[11]
C[ 9]=A[ 1]*B[ 8]+A[ 5]*B[ 9]+A[ 9]*B[10]+A[13]*B[11]
C[10]=A[ 2]*B[ 8]+A[ 6]*B[ 9]+A[10]*B[10]+A[14]*B[11]
C[11]=A[ 3]*B[ 8]+A[ 7]*B[ 9]+A[11]*B[10]+A[15]*B[11]
C[12]=A[ 0]*B[12]+A[ 4]*B[13]+A[ 8]*B[14]+A[12]*B[15]
C[13]=A[ 1]*B[12]+A[ 5]*B[13]+A[ 9]*B[14]+A[13]*B[15]
C[14]=A[ 2]*B[12]+A[ 6]*B[13]+A[10]*B[14]+A[14]*B[15]
C[15]=A[ 3]*B[12]+A[ 7]*B[13]+A[11]*B[14]+A[15]*B[15]

検証に使ったプログラムはこれです。clang++ std-+11で出力しました。

C++11で大文字小文字を区別せずに文字列を検索する

プログラムに慣れていくためにやり始めた Aizu Online Judge は始めて半月ぐらい経過したが意外と続いています。以前にも書いたかもしれませんが、普段のしごとではPLCでラダーを書く事が多いので、あまり言語系のプログラムを書きません。入門書をやっただけで終わっていまいそれ以上のレベルになかなか行けないので、アウトプットするために始めました。

問題をこなしていくたびに、いろいろと発見があるのでそれを書いていくことにします。表題にあるように今回はC++11で大文字小文字を区別せずに文字列を検索することをわかりました。C++では文字列を検索するには。stringクラスのfindを使えばよいのですが、大文字と小文字が区別されてしまいます。<algorithm>にも大文字と小文字が区別しないで検索する方法はありますが、書き方が面倒なようなので、今回は正規表現を使いました。

やり方としては正規表現オブジェクトを作成するときに、大文字小文字区別なしを示すicaseオプションをつけるだけ。あとはregex_match関数で市レベルだけです。

今回の問題は、標準入力で最初に探す元の文字列、次に探されるがわの文字列。END_OF_TEXTで終了という内容だったので、下記のようなプログラムになりました。

#include <iostream>
#include <regex>
using namespace std;
 
int main()
{
    string W,T;
    int count=0;
    cin >> W;
    regex re(W,regex_constants::icase);
    while(1){
        cin >> T;
        if(T == "END_OF_TEXT") break;
        if(regex_match(T,re)) count++;
    }
     
    cout << count << endl;
    return 0;
}

<regex>はC++11から対応なので、C++11を選択することを忘れずに。試しにC++で投稿したら当然コンパイルエラーになりました。

Aizu Online Judgeでプログラムの問題解きを始めた。

プログラムは本で勉強しているが、あまり普段使う機会がない。仕事で使う必要がないというか。プログラムができれば仕事でもいろいろと出来ることがあるのにまだレベルがそこまで行ってない。アルゴリズム題材をどんどん解いていきレベルを上げていこうと思う。今までプログラムの勉強が全然進まなかったので、昼休みの時間を利用してどんどんやっていこう。


まだ始めたばかりなので簡単な問題が多い。出力結果があっていれば正解なので、無駄なことをしていても正解になる。正解はしたが、考え方がいまいちだったなということがある。そんなときに他の人が解いたものを見るとすごく勉強になる。まさに目から鱗が落ちるというかんじだ。

Aizu Online Judgeの問題にはデータが複数用意され、標準入力にゼロが入ったら終了という内容が多い。
普通に考えると、Whileでループで回してif文で標準入力を確認して値がゼロならbreakでループから抜けるという考えだが、While分の条件式で標準入力とANDで結果がゼロであることを確認するという方法があった

int c;
while(cin >> c && c) {
// 処理
}

while は条件式が成立している間ループを続けるが、c++では条件が ゼロ以外のときにロープを続けるようだ。なので1以外の数字でもループを続ける。
もし標準入力だけを条件式にしてみる。

while(cin >> c) {
// 処理
}

するとゼロを入力してもループが終わらない。これは、標準入力のゼロはアスキーコードで入力しているからだ。最初の方法だと標準入力のゼロを変数に入力した段階で、整数のゼロに変換されたので0となり、Whileが終わるということだ。

翻訳はスプレッドシートを使った処理に変えた

前回はGAS スクリプトのLanguageApp.translate 関数を使い、回数制限に引っかかってしまったので、別の方法を考えてみた。それはスプレッドシートにコメントを貼り付けて、その横にTranslate関数をコピーしていくという方法だ。何度か試してみたら、回数制限に引っかからなさそうだ。

処理がうまくきいきそうなので、Webページから処理できるようにした。
ローカルフォルダからファイルをドラッグ&ドロップすると読み込まれてスプレッドシートにコピーしていく。そしてTranslate関数を貼り付けていく。
ドラッグ&ドロップはHTML5のFILE APIがそのまま使用できる。スプレッドシートへコピーはGASへデータを渡し、スプレッドシートへコピーする流れだ。

しかし、Translateが全て終わったかどうかがわからないのが問題だ。実際にスプレッドシートを見ると処理中はLoading…と表示される。これをどうやったらプログラムで判定させればよいのだろう。全然わからなかった。
(サンプルのような数なら、すぐ終わるが、何千・何万項目あると、時間がかかる。)

本当は、一気にコメントファイル出力までやりたかった。しかし、今回はあきらめて別々に処理することに。半自動でやることにした。
手順は以下の通り

  1. ファイルをマウスでドラッグし、Webのテキストボックスの上で離す。
  2. 変換ボタンを押してスプレッドシートへデータを送り、翻訳処理を開始
  3. スプレッドシートを見て翻訳が終わったことを確認
  4. Webページへコメントをコピー
  5. CSVに整形してCSVファイルへ出力する

このような流れにした。自分で使うからこれでいいだろう。
今回は1〜3を作成した。

Google Apps Script (GAS)で試そうとしたら失敗に終わった

前回は出力したCSVファイルをスプレッドシートへ貼り付けて、またコピーしテキストエディタに貼り付け、整形し保存といった手順を一つずつやっていたので、自動化したいと思った。なんなら翻訳Webアプリを作って公開しようかと思った。

GX-Works2のコメント翻訳WebアプリをGoogle App Scripts で作成しようとしたらつまずいた。 GASの制限だった。

GASでの翻訳命令は下記の通り
LanguageApp.translate(comment, "ja", "En")
翻訳関数自体は苦労する余地もない。

csvファイルをGoogleドライブのフォルダに置いて、ファイルをよび出す部分も作成した。ファイルからの読み出し自体はインターネットで検索すればすぐに例が出てくる。三菱コメントの使用どおりUFT-16で読み出せた。これも苦労しなかった。

csvファイルをタブで区切って変数に配列に入れてコメントの部分だけループで翻訳関数にかける。ここからつまずき始めた。

一つは短い時間に使用する回数。translate命令を実行してもう一度命令をするまでの時間が短すぎると、エラーになってしまう。これはタイマーを入れてtranslate命令を使う間隔を1秒待つことで回避できた。

Utilities.sleep(1000)

しかし次は1日の実行回数で引っかかった。おそらく一日でtranslate関数を使うことができる数に制限があるとのことだ。特にGmailと違って特に翻訳関数には記載が無いのに。一回のテストに付きループでtrans関数を何百回とかけていたから、すぐにエラーが出た。おそらく2000回ぐらい使うとなるのだと思う。テストの段階で制限回数に引っかかるなんて・・・。Webアプリにするつもりなら絶対に使えない。違う方法を探さなくては。

コードは以下の通り。