FC2ブログ

次の日常:exist, コマンドライン引数, クラスのpublicにルール?, sstream

if(exist(<引数>)){
continue;
}
なんてしてみると英語で読んだとおりにかけるのだなぁと感心.ただ,実装してるときにはわかりづらい.
こういう書き方をするには当然bool exist(<引数>); で定義すればよいですね.まだboolを自分で使うには抵抗があったけど,
使ってみようかな.


int main(int argc, char* argv[]){
なんて始まるのをいつだか学んだんですが,この引数のことをコマンドライン引数と呼ぶのですね.ううーん.毎回勉強が浅いのかも…


引き継いだC++のプログラムには,ちょっとしたルールを課して作ってあるように見えました.
それは,クラスのpublicなメンバ関数は,他のpublicな関数を参照しないというものです.
意図を汲んでみると,おそらく,publicな関数はクラス外部から定義できてしまうので,それにより望みの機能が意図的であれ故意であれ変わってしまわないようにしているのではないかと.

どれだけ一般なのかわかりませんし,使えるルールなのかはわかりません.小さい実装だからこそ可能なルールかもしれません.
なにかよく知っている方がいればコメントくれるとありがたいです(まだこのブログ成熟どころか卵ですらないんですがね…写真とか写真とか異様に小さい写真とか).


vectorが使えるといいなぁなんて昨日投稿しましたが,同じように,
sstreamをincludeしてostringstreamとかistringstreamとか定義しちゃって,がんばろうと思いました.
文字列苦手ですし.簡単にはto_stringなんてある…みたいな記述も見かけた.
スポンサーサイト



ちょっと日常:三項演算子a?b:c, 列挙体enum, vector, クラスの継承・純粋仮想関数

日常なのであんまり真剣に読まないでね.


突然出てきたらびっくりします.三項演算子.疑問に思う…のがよいかもしれないな.
ただの<条件> ? <真の実行式> : <偽の実行式>
です.これがif()の中にそのまま現れたのです.最初なにかと思いました.
三項演算子?キモッッて中学の頃に見た覚えがあったからすんなり理解できたわけで…


逆に最近にちょっとした記事で見ただけの知識,それが生きたのは列挙体に関して.
列挙体は

enum <識別子> {<要素1>, <要素2>, …} <変数名>;
enum hand {left, right} person;
と書きます.
全然知りませんでした.ちょっと恥ずかしい.
識別子と変数名のどちらかは省略可能.え?意味わかんない…と思ったけど

考えた結果,識別子はクラス名のようなもので,そのクラスの構造を持つものをいろいろ用意できる…いや,だから識別子なんですけど.こっちは容易に理解できるし,私の見たenumもこれだった.変数名はクラスを定義した後に変数を作るのと同じ感覚.
じゃあ識別子を書かないって?役割を持たせた列挙体を一つに限って用意したいとき(があるのか・・?),実現できます.他に使い道は浮かばないので,どう使うかが問題の気がします.

そもそものenumの使い方?中身?としては,例えばhand::leftと書いてみたりするんですが,leftにはint型の0が,rightにはint型の1が列挙変数に関連付けられています.とはいえ,hand = 0;とするのは定義されておらず,hand = (enum hand) 0;という形が標準です.暗黙の型キャストはコンパイラ依存と言えます.
また,switch文ではswitch(hand) { case: left …と書くことができる.


vectorが使えたら私もデータ処理とか楽しめるんじゃないかと思って,やり始めました.
結果はでてないけど.
とりあえずvector.push_backでデータを一個追加することができると知ったよ.どう追加されてるのさ…
一次元データがどう格納されて,push_backやpop_backは最後尾で行われるかとか,そういう点を理解しなきゃいけない.
あと二次元データの扱い方があればそこも勉強しなきゃ.


さて,まとめたかったクラスの継承.そういうものがあるっていうことだけは知ってたけど,まとめて読んだのは初めてだった.

・クラスの継承は":"でおこなう.: public <親クラス名>とかprivate <親クラス名>とか.
親クラスのpublicメンバ関数をpublicで継承したいときにpublic指定,privateで継承したいときにprivate指定するだけ.
・メンバ変数を初期化して継承するには<親クラス名>に続いて","を置いて,<メンバ変数1>(<値1>), <メンバ変数2>(<値2>),…としていく.
・virtualでメンバ関数を仮想関数に.すると継承した子クラスで再定義ができるようになる.
・純粋仮想関数virtual <メンバ関数名> = 0; 関数の実体を定義せず,継承される前提で仕組みを内包させておく使い方だろうか.
・抽象クラスとは,純粋仮想関数などを使って実体を作らないクラス.実体を作れない…そのことを「インスタンス」という言葉を使っていたけど私にはまだわからなかったな.
・public,privateの他にprotectedというものがある.親クラスで使って,その時点ではprivateと同じだが,継承クラスでpublic扱いで継承される.
・他にも,子クラスのpublic内でusing <親クラス名>::;なんてすると親クラスで定義しつつも使えないようにしてあった関数を,親クラスで行った実装を引き継いで使うことができます.これはちょっとした発見だったな.
・あと,親クラスのデストラクタはvirtualにしとかないとね,と.
・他には,this->ってなんだよ!とか.いや,そのままなんですけどね.クラスの実装の中で,メンバ変数をいじるときにthis-><メンバ変数名>と書く・・はず.


こんなとこかな.うーん,文にしてまとめるには多すぎるし何より教科書的な内容だから箇条書きのままで.
それでは.

batファイルを作ることになったメモ

今までbatファイルを(Qt同様に)引き継いで使っていたわけですが,
それを読んだりちょっと変更するだけでなく,自分で作る必要がついに.

改めてbatファイルの様々な構文の,いろいろな使い方というのを知りました.
そのサイトやら,使ってみた方法などをメモしていきます.
ヘッダー(&フッター),コメントアウト,変数の取扱い,for文,ファイル入出力,他のbatファイルの実行,待機までまとめます.
他のファイルの実行,ちょっと説明が怪しいので書かないことにします.そもそもプログラミングの理解が足らないような…

主にこちらを参考にして書きました.
開発に約立つ,BATファイルの書き方・パターン集

batファイルを読み込んでコマンドライン操作をする場合が前提です.打ち込むのが面倒だし間違ってたらすぐ直せるという必要からです.まずは頭に
@echo off
SETLOCAL enabledelayedexpansion
といれちゃってからコメントしましょう.
一行目の@echo offがないと,読み込んでいったものが全てechoされます.つまり,読み込んだ文を一行ずつ,そのまま出力してくれます.邪魔,切る.
次の行のヨクワカラナイ長いやつは,変数の遅延展開を可能にするコマンド.batの環境変数は即時展開と遅延展開というものがあり,値が更新されていくようなものを使う場合...forなど...には遅延展開の宣言が必要です(変数の項で即時展開,遅延展開の書き方を説明します).
遅延展開の宣言は,SETLOCALからENDLOCALまでの間です.頭にSETLOCALを宣言したので,batファイルの最後にENDLOCALしておきます(実際は省略可能のようです).

rem ~~~
コメント化する命令です.
その行の最初にrem(ember)を書けば,行全体が命令ではない文として認識されます.

rem set 変数名=格納する値
set mydomain=amefuriyame
set mypath=fc2.com
set myhtml=%mypath%.%mydomain%

set /a iter1=1
set /a iter1=!iter1!+1
set /a iter1=!iter1!+1
変数を定義します.
setは他にも色々使い方はありますが,変数に関して言えばsetが使われるわけです./a(rithmetic)は,=の後の文を式として読み込むものです.例えば,"1+1+1"という値の入った変数を/aで代入すると3になって格納されます.

%~~%と囲めば,変数の即時展開ができます.これにより,例えばecho %myhtml%とすれば,出てくるのはfc2.com.amefuriyameです.全然ドメインでも何でもないですが.
!~~!と囲めば,変数の遅延展開ができます.これにより,実行されたときに値が変化してくれるので,最後までiter1を読むとecho !iter1!は3と返ってきます.

…実はこの場合,!~~!ではなく%~~%でも同じ結果がでます.ちょっとびっくりしましたが,「実行されたとき」というのが何と対比しているのかが重要でした.比べられるのは「読み込むとき」です.
読み込むときに,読み込んだブロックごと変数を代入してしまうのが即時展開%~~%.読み込むブロックというのは例えばif判定してから真なら実行する中身までの全て.for文で実行する中身の全て.
今回はそういうブロックに相当するのが一行ずつです.さて,ブロックを作ってみましょう…
set iter1=1
(
set /a iter1=!iter1!+1
set /a iter1=!iter1!+1
)
むだにカッコを前後につけるだけです.
この状態で色々なところにecho !iter1!やらecho %iter1%やらやってみると,感覚がつかめると思います.
(set iter1=1もカッコの中に入れてしまうと,echo %iter1%はただのechoと同じになる,という点だけ注意すると比較できるでしょう.)
参考:遅延環境変数とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

さて,for文ですが,いろいろなオプションで様々なことができます.
参考:.bat(バッチファイル)のforコマンド解説。
今回は使った/L,/Fオプションだけ紹介./Lが数値を更新していくfor文,/Fがファイルを扱う文です.
for /L %%i in (1,2,10) do (
echo %%i
set /a twice=%%i*2
echo !twice!
)
for文の変数は%%と2つ重ねて.
(1,2,10)は1から始まり,2ずつ増やし,10を越したら実行しないという意味です.減らすことも可能で,整数です.
/Lを使わない場合,(1,2,10)の代わりに整数リストを配置します.リストは使ってないのでわかりません.参考に示すようなやり方をすればなんとなくでもできます.
参考:新潟工科大学 情報電子工学科 4.2 for文

echo HeaderMsg > file1_3.txt
for /F "skip=4 tokens=1,3 delims=," %%a in (file1.csv) do (
echo %%a
echo %%b >> file1_3.txt
)
ファイルを扱うためのforです.参考:外部ファイルを読み込む
file1.csvの先頭4行をskipし,","で区切って読み,1列目と3列目をaに続く変数に格納する.それを行がなくなるまで繰り返す.と読みます.
aに続く変数に格納ってなんだよ,って話ですが,tokensで指定した個数(今回は,1列目と3列目を格納するので2個)だけ,a,b,c,…と勝手に宣言して格納してくれます.ということで,aをechoして,bをfile1_3.txtに書き出してもらいました.
>1個でファイルは初期化されます.>>と2個になるとファイルの最後尾に追記していく形です.file1_3.txtはHeaderMsgという文字列で初期化されました.その後,file1.csvの3列目だけがfile1_3.txtに記録されます.
以上,ファイル入出力を同時にやりました.

待機するのにwaitもsleepもないということで
ping localhost -n 5 > nul
が提案されています(一番最初に紹介した参考ページ).なんだか,面白い.

pauseというコマンドもあります.pauseは待機ではないですが,入力待ちになるものです.使えばわかります,これかー!,と.

以上,batファイルの加工現場でした.

Qtでプロジェクトを引き継いだときの諸問題の解決

統合開発環境初心者(IDEってコレダヨネ)がQtのプロジェクトを引き継いで運用することになりました.
運用って言っても内輪で使う程度のもので,現状で完成してるから引き継ぎできるよう維持していってという程度なのだけど.

そんな私が早速維持できずに,スタックしたわけです.悲しい.

PCに関してはWin10, 64bit程度だけ言えばいいですかね.

まず,Qtをインストールします.そこからスタック.
全く気づかずに,QtのうちVS2015でコンパイルする版をインストール.しかし私のPCにはすでにVS2017がインストール済み.
2015に戻る必要もないのにインストールしたモノ自体に目がいかず,なんでコンパイルできないのーなんてただやって1週間.
アホですね.

気づいて,QtのMinGWのやつをインストールし直す.
Qt Creatorを起動.とりあえずコンパイルぽい動きはしてくれた.
早速エラー.なんだろう.なんだ…これは…
(時刻): ディレクトリ "C:\Users\~~~\" Util.asciify("build-(ソフトの名前)-Desktop_Qt_5_6_2_MinGW_32bit-unknown")" でエラー: TypeError: Property 'asciify' of object Core::Internal::UtilsJsExtension(0x35fb720) is not a function" を作成できませんでした
と出る.これはすぐ解決して,Qt Creatorの左タブにある「プロジェクト」で,
debugでもreleaseでも,シャドウビルドのチェックボックスを切っておく.

そして,47個のエラーを吐きながらも,exeファイルを生成してくれた.前任者もそのまま残していったエラーだろうと踏んで,exeの実行にかかる.
さあ,exeを実行してみよう(release版を実行するけど,debug版でやると後ろにdが付いたdllファイルを言われるよ).
エラー.
Qtエラー
こんな感じってよくありますよね・・で,
Qt5Core.dll
Qt5Gui.dll
Qt5Widgets.dll
libgcc_s_dw2-1.dll
をまず最初に言われます.
この点に関して,似た記事はこちら.
うぇぶとらばぁす 作ったアプリケーションの実行
どこにあるのかな,と探すとインストールしたQtのフォルダの中にあります.
ちなみに,私がやった順で説明しますと
C:\Qt\Qt5.6.2\Tools\QtCreator\bin
C:\Qt\Qt5.6.2\Tools\mingw492_32\bin
から引っ張ってきて,exeのあるフォルダにコピーしました(QtとMinGWのインストールしたバージョンはフォルダ名の通りです).
これが…実は間違いだったのですが.続けて,実行すると
libstdc++-6.dll
libwinpthread-1.dll
が足りないよといいます.Qt系じゃないのでMinGWにあるだろうと思って探してちゃんとあります.同じくコピー.
さあ実行.
え?技術的に私が及ばなそうなエラーが来ました.
プロシージャ エントリ ポイント _Z4endlR11QTextStreamがダイナミック リンク ライブラリ
C:\Users\~~~\(実行したexeファイル名) から見つかりませんでした。
ちょっと頭が働いた私はダイナミックリンクライブラリがdllだということに気が付きます.しかしこれは,結果的にヒントになりませんでした(正しいわけですが).ずっと空回りして1週間を費やしたのです.
結論を先にいいますと,dllを取ってくるフォルダが間違っていたというものです.正しくは
C:\Qt\Qt5.6.2\5.6\mingw49_32\bin
から取ってくればよいです.すると正しく実行できます.この記事を読む人は,すぐ解決できるでしょう.
ちなみに,exe実行時の初めのエラーを検索した方は,Toolsのフォルダからコピーすればいいという記事を見つけるはずです.それは間違っている…少なくとも私の例ではそうなりますので,お気をつけて.
なぜ2種類あるのか…実は2種類以上あるんじゃないのか…という問題ですが,これはかんたんに言えばdll hell(dll地獄,dependency hell)という事柄のようです.

dllを取ってくるフォルダの違いに気づかなかった私は,エラー自体の理解やらQt Creatorでのコンパイルし直しなどをいろいろ試します.
そこら辺のエラー内容などを全てまとめておくので,吸い寄せられるようにここにきて解決する人がいるといいなぁと思います.

まず,エラーについてです.
私にはプロシージャエントリポイントなんてわかりませんが,つまりは,
dll(今回は実行したexeファイルそのもの)内に_Z4endlR11QTextStreamなんて関数はないよ,dllに入ってるって君(実行者?)は言うけど入ってなかったよ
ということのようです.このエラー自体はとてもよく起きるようで,dll hellと強く関連します.

一例だけ,理解したレベルで紹介してみます.
dllはライブラリを動的にリンクするものです.dllに入っているような処理内容を実行ファイルごとに全て入れる必要がなくなり,省スペースであるという点が重要です.一軒家に家族人数分のトイレがあったら家は窮屈です.1つくらいのトイレをみんなが必要なときに参照するのがいいでしょう.地区に役所が個々人の人数分設立されていたらとてつもない無駄です.dllはそういうものだと簡単に理解しています.
そんなdllですが,例えば内部に間違い,プログラムで言えば欠陥が存在すれば,直して更新せざるを得ません.以前のdllのバージョンと互換性があればよいですが,互換性がなかった場合に問題がおきます.
古いdllで開発されたものが,新しいdllを参照してプログラムを動かし,互換性のない部分に触れた場合.よくてエラーして終了です.悪ければブルースクリーンやそれ以上にでもなるんじゃないでしょうか(そのくらいの感覚でdllを触ったほうがよいという意味です).

今回,dllを入れ替えただけで直ったんですが,なぜエラーの示したものがdllではなくexe実行ファイル本体だったのか,私には結局わかりませんでした.exeにということはdllでななくc,cppやhファイルかと思ったんですけどね…

次に,Qt Creatorでコンパイルし直してみると何が起きるのか,書き残します.
デバグ開始します.
実行失敗
During startup program exited with code 0xc0000139.
とポップします.
また,そんな状況で「実行」をしてみます(Qt Creatorの左タブ下の方のやつです).
アプリケーション出力に
C:\Users\~~~\(ファイル名).exe を起動中...
プログラムが突然終了しました。
C:\Users\~~~\(ファイル名).exe がクラッシュしました。
と出力されます.
なぜこうなるのだろう,という推測です.
dllを読み込むには環境変数を使っているでしょう.その優先順位が,Qt Creatorでの実行時,通常実行時とで共に現在のフォルダ(exeファイルのあるフォルダ)が初めの方にあるのだと考えてます.誰かチェックして.
持論を続けますと,Qt Creatorで実行するときには,ソフトが例えば
..\
C:\Qt\Qt5.6.2\5.6\mingw49_32\bin
C:\Qt\Qt5.6.2\Tools\QtCreator\bin
C:\Qt\Qt5.6.2\Tools\mingw492_32\bin
という優先順位でdllを探索してくれてるとか.そんでもって通常実行時にはC:\Qt\らへんのなんて参照してないとか.
だから通常実行時に「オイ.dllねえぞコノヤロウ」と言ってきて,私が間違って優先順位の低い方からdll引っ張ってきたばかりに,その後ではQt Creatorでも通常実行でも起動しなくなる(プロシージャエントリポイントのエラー)のではないか,と考えます.

実際,環境変数を調べてみるとシステムのも含めQtフォルダのものはありませんでした.
%SystemRoot%がどーのこーの言ってる海外のフォーラムもあったけれど…知らない…なにそれ.多分関係ないんじゃない?

持論を支えるにはもう2つくらいチェックする項目あるけど,誰かチェックして.
1.dllのバージョンチェック
2.Qt Creatorでコンパイル・実行時のdllやheader,cpp等を読み込む設定

力尽きた.参照したサイトが載っていないのは,今回ほんとにいろんなところを探索しすぎてきりがなかったから.
あ,ちなみにプロシッジャエントリポイットのエラーのときに,dllが足りないのでは??と考えて,dependency walkerというのも試しました.
exeファイルが参照するdllを読み込んでくれるソフトです.更新がされておらずAPI-WIN-??系だかなんだかを認識してくれないという問題はありますがそれはdependency walkerと共にネットですぐ知れます.それをチェックした上で,足りないものはなかったわけです.それでdllのバージョン違い,という問題に対処することを思いつきました.

dependency walkerの使い方のレクチャー(英語) How to generate Dependency Walker log files for Customer Support
Qt Creatorの使い方のレクチャー(英語) C++ Qt 84 - User Feedback how to deploy an application
両方共youtubeですが,見てません.そんな英語力まではないです.後者を見ることで解決したというフォーラム(こちら)は有りました.

この件,あまりにもフォーラムが少ない.日本語も英語も.なぜか勝手に直って捨ててるスレが数件あるというのも問題….

int main(void)とデストラクタ~とexternを知る

C/C++を高濃度に触ることになり困惑中.
そもそもわかんないよね,なんて思ってる部分を再確認.
mainの引数,戻り値は?
https://oshiete.goo.ne.jp/qa/2445252.html
ただの知恵袋.
答えは,
int main(void)
int main(int argc, char *argv[])
で.前者は引数キニシナーイ.後者は,argument countとargument valueの並び.
https://teratail.com/questions/7310
によると,argcで引数の数を示し,argvで引数に書いてあることを読んでるみたい.そう受け取った(仕様読めよ)
class Hoge{
public:
Hoge(){
----;
};
----;
~Hoge();
}
つまり私はclassの勉強不足なんですよ.
疑問に思ったことは,~Hogeってなに,でした.
なんで同じ名前のやつのチルダがあるの.ははは…;

https://www.s-cradle.com/developer/sophiaframework/tutorial/Cpp/ctordtor.html
クラスオブジェクトが作られる際,はじめに実行されるのがpublic内にあるHoge().これ,コンストラクタ.
一方で,クラスオブジェクトが捨てられる際に実行されるのが~Hoge().こっちがデストラクタ.
引数は指定できても戻り値はない.あっても困る気がする…
簡単に言えば,コンストラクタは初期化,デストラクタは後始末なのだから,うまく行ったかどうか以外に戻り値に意味はないし.

いや,うまく行ったかどうかって大事だけど…boolとかで大事に扱ってるのを知ってはいるけど…コンパイル時点で問題があるか判別してくれてたりしないかな.class内なのだし.コンパイラでのチェックは容易そう.それを理由として戻り値がない,とかであってほしい.

そんなこんな調べてるうちにこんな記事.
http://d.hatena.ne.jp/u_1roh/20091108/1257673753
引用
むしろ、次のようなコードがC/C++への「入り口」としてふさわしいんじゃないか。

extern "C" {
__declspec(dllexport) int HelloWorld() { return 0; }
}
え?
全くわかりません.

とりあえず一時しのぎとして,extern "C"ぐらいは調べました.
http://d.hatena.ne.jp/debian36/20080227/1204109794
マングリングを防ぐのに使われる,という記事.
なんかちがう.多分焦点のずれた記事を読んでいるのだろう.

ということで,またの機会に.
プロフィール

satsuki

Author:satsuki
記事を消しつつ、ころころ変えながら運用中

最新記事
最新コメント
月別アーカイブ
カテゴリ
訪問者数
検索フォーム
リンク
QRコード
QR