X



C++相談室 part144

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
垢版 |
2019/07/22(月) 13:18:35.52ID:gptRHpgT
C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。

前スレ
C++相談室 part143
https://mevius.5ch.net/test/read.cgi/tech/1560574313/

このスレもよろしくね。
【初心者歓迎】C/C++室 Ver.105【環境依存OK】
https://mevius.5ch.net/test/read.cgi/tech/1556142878/

■長いソースを貼るときはここへ。■
 http://codepad.org/
 https://ideone.com/

[C++ FAQ]
https://isocpp.org/wiki/faq/
http://www.bohyoh.com/CandCPP/FAQ/ (日本語)

----- テンプレ ここまで -----
0489デフォルトの名無しさん
垢版 |
2019/08/17(土) 11:16:45.62ID:AIpU/gsR
いくら便利なものがあるといってもさすがにC++をナマポや自前RAIIの知識なしで使うのは不可能だから、
初心者は最初はメモリ破壊で苦しんだ方がいいと思うわ
0490デフォルトの名無しさん
垢版 |
2019/08/17(土) 18:58:14.86ID:RHoMoFJP
https://ideone.com/10xlAn
ギャグなんですけど、
これファイル間またいで定義したい時って何か特別な事しないといけなかったでしたっけ?
「日本語C++」書いてみたい人生だった。
0492デフォルトの名無しさん
垢版 |
2019/08/17(土) 19:24:45.74ID:RHoMoFJP
>>491
検証ありがとう。自分はVCなんだけどね。書き忘れてごめん。
VCも無理かな。

最近プリプロセッサは、すたれる流れのようなのでメンテされてないのかなぁ・・・。
0493デフォルトの名無しさん
垢版 |
2019/08/17(土) 20:52:47.23ID:pwn7XyQd
マクロは名前空間に閉じ込めることができないからしょうがない
0498デフォルトの名無しさん
垢版 |
2019/08/18(日) 09:51:15.20ID:aqKQgKLg
もし i == 0 なら
printf(">>497 はちょっと頭悪い");
もしくは
printf(">>497 はちょっと頭弱い");

…なるほど正しいかも

ってそんなわけ無いだろw
0499デフォルトの名無しさん
垢版 |
2019/08/18(日) 10:01:09.98ID:X/aF/qdA
>>80
>Pythonは「CPythonの実装が規格だ」だし

それrubyと勘違いしてないか?
明文化されていない仕様なんてそんなに残っていないと思うが。

あと、MATLABはアカデミック分野では少なくともRやOctaveなんかより
信用されていると思うよ。
0501デフォルトの名無しさん
垢版 |
2019/08/18(日) 10:49:51.48ID:kvaoi5YP
make環境を作ると更新ファイルだけコンパイルしてくれたり、色々便利そうなので
コンパイルコマンド直たたきからmake環境に移行しようと考えています。

下記で正常動作しているので、これでmake環境を作りたいと考えていますが
「c++ make」で検索してもあまり情報がないため苦戦しています。
どのように書けば良いかわかりますか?もしくは参考のURLなどあれば教えていただけないでしょうか。

#!/bin/sh -
export CC=~local/bin/gcc
export CXX=~local/bin/g++

g++ -c -g -Wall -pthread -std=c++11 ./Func.cpp -lm -lz -Wextra -o Func.o &&
g++ -c -g -Wall -pthread -std=c++11 ./Main.cpp -lm -lz -Wextra -o Main.o &&
g++ Main.o Func.o -o main.exe -lz
0504デフォルトの名無しさん
垢版 |
2019/08/18(日) 11:22:19.79ID:aqKQgKLg
>>501
簡単に言えばMakefileに

作ってほしいファイル名: そのファイルを作るのに必要なファイル
(タブ(なぜか空白はダメ))作るためのコマンド

をズラズラ書いておけばいい
なのでその例だと

Func.o: Func.cpp
 g++ -c -g -Wall -pthread -std=c++11 ./Func.cpp -lm -lz -Wextra -o Func.o

Main.o: Main.cpp
 g++ -c -g -Wall -pthread -std=c++11 ./Main.cpp -lm -lz -Wextra -o Main.o

Main.exe: Main.o Func.m
 g++ Main.o Func.o -o main.exe -lz

って書いておいて(わかると思うがg++の前はタブな)
make Main.exe
ってやればいい
毎回Main.exeを指定するのが面倒なら
Main.exe: Main.o Func.m
 g++ Main.o Func.o -o main.exe -lz
の行を一番上に持って行けば make だけで作成できる
(makeは指定がないと最初に見つけた作りたいファイルを作ろうとする)
0505デフォルトの名無しさん
垢版 |
2019/08/18(日) 11:59:20.99ID:XCKtcmfj
>>501
以下の文献とオライリーのGNUmake読んで、あとは自分で考えるのが良い。
http://aegis.sourceforge.net/auug97.pdf
この辺り、まともに理解してる奴が本当に少ないから。
だからconstexprとかboostとかクソみたいなものをありがたがるんだろうなと思う。
0507デフォルトの名無しさん
垢版 |
2019/08/18(日) 12:06:43.92ID:XCKtcmfj
>>506
ビルドと言語機能は綿密に絡み合ってるから。
c++使っててこれだけ当たり前の話を理解できないというのが理解できない。
0508デフォルトの名無しさん
垢版 |
2019/08/18(日) 12:20:14.52ID:aqKQgKLg
> ビルドと言語機能は綿密に絡み合ってるから。
具体例の1つも出せないクズ乙
0515デフォルトの名無しさん
垢版 |
2019/08/18(日) 12:54:48.15ID:rdsOEwya
素のMakefileは最終的なオブジェクトファイルとヘッダファイルの依存関係を書き下すのが大変に面倒臭い
なぜなら、
 Target: Dependencies1 Dependencies2 ...
 (TAB)Command
という記述において、Commandが具体的にTargetお生成しないと事実上立ち行かないので、
インクルードファイルAがインクルードファイルB、Cをインクルードしているという状況を
 A: B C
 (TAB)echo Hello World!
などと書くわけには逝かず、あくまで
 foo.obj : foo.cc A B C
 (TAB)gcc foo.cc
式に.objなターゲットに対して関連付けねばならない
ファイルがあるだけで勝手にヘッダファイルの依存関係を解決させることは
GNU Makeの昨日とシェルコマンドを組み合わせてできた気がするが(忘れた
たかがこれだけのためになんでそんな糞面倒なことをせねばならんのじゃ、というキモス

※ 個人の感想です
0516デフォルトの名無しさん
垢版 |
2019/08/18(日) 13:00:42.47ID:26pp6bRY
Ruby のRake, Thor などのタスクランナーで、コンパイル出来ないのか?

Webpack, Gulp とか
0517デフォルトの名無しさん
垢版 |
2019/08/18(日) 13:02:29.42ID:XgJSnVlI
C++のモジュールシステムはいけてないよね
という話ならわかるが、
constexprとboost?
全く意味がわからねぇ
0519デフォルトの名無しさん
垢版 |
2019/08/18(日) 13:34:10.37ID:jp7+H4+a
一応昔はコンパイル単位がすなわちモジュールとして機能していたはずだったのに、どこで間違えたんだろうな
0520デフォルトの名無しさん
垢版 |
2019/08/18(日) 14:46:24.52ID:aqKQgKLg
>>501
簡単に言えばMakefileに

作ってほしいファイル名: そのファイルを作るのに必要なファイル
(タブ(なぜか空白はダメ))作るためのコマンド

をズラズラ書いておけばいい
なのでその例だと

Func.o: Func.cpp
 g++ -c -g -Wall -pthread -std=c++11 ./Func.cpp -lm -lz -Wextra -o Func.o

Main.o: Main.cpp
 g++ -c -g -Wall -pthread -std=c++11 ./Main.cpp -lm -lz -Wextra -o Main.o

Main.exe: Main.o Func.m
 g++ Main.o Func.o -o main.exe -lz

って書いておいて make Makefile Main.exe
0521520
垢版 |
2019/08/18(日) 14:48:27.09ID:aqKQgKLg
スマン、間違えて二重投稿になっちまった
0522501
垢版 |
2019/08/18(日) 14:57:48.84ID:kvaoi5YP
>>503
CC, CXXは個別インストールしているgccがあり、以前何かのモジュールをインストールしたときに、元からある
/usr/bin/g++
に関連したライブラリパスが使われることがありこれを設定しました。
今回の単純コンパイルには不要かもしれませんが、おまじないで残していました。

>>504
ありがとうございます。
基本はコマンドを並べていけばいいんですね。
何も指定しない時には先頭のものを指定したことと同じになることも参考になりました。

>>505
このあたりもちゃんと理解できるようになりたいです。
少しづつ勉強したいと思います。

>>512
こんなのもあるんですね。
これも調べてみたいと思います。
0523501
垢版 |
2019/08/18(日) 15:01:32.97ID:kvaoi5YP
>>521
いえいえありがとうございます。
まずは単純羅列から入ってCXXFLAGS、OBJS、LIBSなどを使いこなしていこうと思います。
0524◆QZaw55cn4c
垢版 |
2019/08/18(日) 16:31:44.67ID:16gP3sh0
>>512
それらが make に比して優れた点はなんでしょうか?
0525デフォルトの名無しさん
垢版 |
2019/08/18(日) 17:11:35.03ID:ToM84NKx
>>517
横からすまんが意味はわかる
c++はコンパイル時になんでもかんでも解決しようと必死すぎ
フェーズ分けてbinutils使いこなした方が素直と思うことが多々ある
0529520
垢版 |
2019/08/18(日) 19:26:20.54ID:wYOmB27V
>>525
ますます意味わからんw
0531デフォルトの名無しさん
垢版 |
2019/08/18(日) 19:35:39.45ID:ToM84NKx
スキル不足なのに見下してるやつに教えてやる義理はないんだよね
逃げますね
0533デフォルトの名無しさん
垢版 |
2019/08/18(日) 22:23:44.93ID:JoepZ2Id
>>525
国際標準になってないbinutilsなんて使ったら、環境依存でコンパイル通らなくなったりする。
0534デフォルトの名無しさん
垢版 |
2019/08/19(月) 03:39:22.51ID:uhqBoit2
VC++2017で std::string str = "abcd";ってやると
debugモードだとビルドできてるのに
ReleaseモードだとLNK2001エラーが出てしまいます

他に何か宣言かlibがいるのでしょうか
昨日一日この点で一日悪戦苦闘していました

ちなみにプロジェクトはコンソールアプリで
リンカーのシステムは処理の都合上、Windows(/SUBSYSTEM:WINDOWS)にしてあります
0537デフォルトの名無しさん
垢版 |
2019/08/19(月) 07:12:08.46ID:p1963chb
>ファイルがあるだけで勝手にヘッダファイルの依存関係を解決

俺はこれカスタムして使ってます
https://postd.cc/makefile-c-projects/
0538デフォルトの名無しさん
垢版 |
2019/08/19(月) 09:00:35.28ID:uhqBoit2
>>535
いつの間にかReleaseの方ばかり設定いじるというアホなことやらかしてました。
プロジェクトを作り直してソースをコピーすることで解決しました。
0539デフォルトの名無しさん
垢版 |
2019/08/19(月) 09:12:20.21ID:uhqBoit2
VC++2017でコンソールアプリとしてプロジェクトを立ち上げました。
しかし、コンソール(dos窓)を非表示にするべく
構成プロパティのリンカー→システム→サブシステムを
Windows(/SUBSYSTEM:WINDOWS)にしてwindows.hをincludeして
int main(void)からint WINAPI WinMain(void)に変更してビルドすると
「C2731 'WinMain':関数はオーバーロードできません」と言われました。

構成プロパティのリンカー→詳細設定→エントリ ポイントをmainにしてビルドしても
結果は変わらず、int main(void)に戻すと大量にエラーが発生しました。

この場合、どうすればよろしいのでしょう?
0542デフォルトの名無しさん
垢版 |
2019/08/19(月) 09:37:33.04ID:rfX59j2s
>>539
なぜ手でsubsystem変えようとしてんの?
VSのテンプレートそのまま使えばいいじゃん
それができないならその理由を説明すべき
0543デフォルトの名無しさん
垢版 |
2019/08/19(月) 09:40:50.85ID:uhqBoit2
>>540-541
ありがとうございます。
以前ググって見つけたものをだまされたと思って
int WINAPI WinMain(void)から
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char* lpCmdLine, int nCmdShow)に
変更したらReleaseモードでも上手くいきました。
でも、元が(void)なんで、引数の設定に釈然としないところありますが…
0544デフォルトの名無しさん
垢版 |
2019/08/19(月) 09:43:45.91ID:uhqBoit2
>>542
普通にやったらどうしても大きなdos窓がしばらく現れるので
(処理の都合上system関数からのexe実行が必要だからです)
ググって調べたらそういう風にいじれと書いてあったからです。
0553デフォルトの名無しさん
垢版 |
2019/08/19(月) 21:23:04.43ID:78Wz1qhX
unifyde call syntax => 邪道。

でも、欲しいのである。
関数型食えると思うんだけどなー。
0554デフォルトの名無しさん
垢版 |
2019/08/19(月) 23:23:04.65ID:ZU65OOaB
バイトデータの比較を高速に行いたいのですが、以下@Aを考えました。
連続したバイトデータを比較するのに下記以外に簡素に書ける方法はありませんか?
memcpyはコピーが発生するのでちょっと遅くなるかなと思っています。

int main(){
unsigned char byte[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
// @1バイトずつ比較
if( byte[2] == 0x03 && byte[3] == 0x04 && byte[4] == 0x05 && byte[5] == 0x06 ){
printf("yes\n");
}else{
printf("no\n");
}
// Aビット演算した結果を比較
if( (byte[2] << 24 | byte[3] << 16 | byte[4] << 8 | byte[5]) == 0x03040506 ){
printf("yes\n");
}else{
printf("no\n");
}
}
0555デフォルトの名無しさん
垢版 |
2019/08/19(月) 23:35:28.83ID:78Wz1qhX
std::int8_t A[]={0,1,2,3};
std::uint32_t* B=(std::uint32_t)A; //care align.

if(*B == 0x03020100){
//yes.
}else{
//no
}
SIMDライクな感じで比較できる気がするけど、おススメはしない。
エンディアン注意。
0556デフォルトの名無しさん
垢版 |
2019/08/20(火) 00:09:06.19ID:C94+kmpU
クヌース-モリス-プラット法とかボイヤー-ムーア法とかやらんかい
ttps://nebuta.hatenablog.jp/entry/20110127/1296115997
0557デフォルトの名無しさん
垢版 |
2019/08/20(火) 01:22:04.58ID:PxgCmY+k
>>554
memcmp とか std::equal とか。速度はどうなるかわからないので推測じゃなくて実測でよろしく。
0560デフォルトの名無しさん
垢版 |
2019/08/20(火) 02:14:14.18ID:HUUEwIaK
>>554
少量のメモリ上の値比較やコピーの処理時間なんて無視できる程度で考える必要もない。
大量のデータの比較を行うとしたら、その大量のデータがメモリ上に存在するために多くの場合はファイルI/Oなり通信なり演算なりしているはずで、そちらのコストの方が桁違いに大きいから単純な比較処理のコストを気にするのは無意味。
ほんとに気にする必要があるのか、まずは確認すべきだろう。つまらない高速化を考えるより、可読性の高い素直なコードを書いた方がいいよ。
0561デフォルトの名無しさん
垢版 |
2019/08/20(火) 13:11:19.02ID:20EaQULd
高速化って言ったら、やっぱりよく使う変数をレジスタに割り当てることが大事だよな
メンバ変数は毎回メモリとやり取りするので遅くなるから
ループ外で自動変数に読み込んでから使うとビックリするぐらい速くなったよ
0564520
垢版 |
2019/08/20(火) 13:57:22.86ID:vf53Ia55
(日記はチラウラに)
0567デフォルトの名無しさん
垢版 |
2019/08/20(火) 14:29:19.64ID:aHZAynoR
よくあるような、
if ( (c >= 'A' && code <='Z') || (c >= 'a' && code <='z') ||
  c == '_' ) {
 ・・・
}
の部分を、条件jmp文が少しでも少なくなるようにと思って、
予め作成しておいたテーブル(配列)を使って、
if ( eiji_or_underscore[c] != 0 ) {
 ・・・
}
として実測してみたところ、何度計測しても後者の方が遅くなった。
アセンブリコードを見てみても、前者だと5つの条件jmp命令、後者だと1つの条件jmp命令と、
後者の方が命令数が少なくっていた。しかし、前者だと、レジスタとcmp命令を使っていたが、
後者だとグローバル変数の配列を読み出しに行っていた。

最近のCPUは非常に複雑で高度な「分岐予測」をしていて、配列は読み出してみないと
値が分からないので、「予測」ができず、分岐予測の「予測間違い」がおきるが、
レジスタをcmpで比較する場合には予測が出来るためだろうか。

しかし、昔より最適化する際にどっちが高速になるかの予想が難しくなってしまってる。
0568デフォルトの名無しさん
垢版 |
2019/08/20(火) 14:39:39.94ID:aHZAynoR
>>567
誤:if ( (c >= 'A' && code <='Z') || (c >= 'a' && code <='z') ||
正:if ( (c >= 'A' && c <='Z') || (c >= 'a' && c <='z') ||
0570デフォルトの名無しさん
垢版 |
2019/08/20(火) 14:48:01.70ID:lOKfo+mN
最近の環境では「実測」の信頼性確保も、また難しいです。
なぜかある時には何度測定しても遅いのに、あらためて別の時に
測ると速く出る事があったりします。
0573デフォルトの名無しさん
垢版 |
2019/08/20(火) 15:08:33.40ID:aHZAynoR
理論上は、メモリがキャッシュに乗っている限り、メモリの読み書きとレジスタ
への読み書きの速度は同一です。

ただし、メモリとメモリは add, sub, mov 命令で2つのオペランドに同時指定は
出来ないのに対し、レジスタは出来るので、確率的にレジスタの方が必要な
命令数が少なくて済むので高速になる場合があります。
あとキャッシュに乗って無い場合はメモリは遅くなります。
0575デフォルトの名無しさん
垢版 |
2019/08/20(火) 15:23:45.52ID:hCU5dYnH
あ、すまん俺の方が間違えてた・・
まさかとは思うけど最適化してないとか無いよね
0576デフォルトの名無しさん
垢版 |
2019/08/20(火) 15:29:52.16ID:lOKfo+mN
>>575
最適化はどちらも同じオプションでしてますし、出力されたアセンブリ・コード
も見て、テーブルを使った方が命令数の少ないコードになっていることも
確認してます。条件jmp命令も少なくなっています。
0577デフォルトの名無しさん
垢版 |
2019/08/20(火) 15:30:02.90ID:hCU5dYnH
あと前者のコードは与えたcの値がA-Zだと分岐の回数2回で済むからじゃないかね
0578デフォルトの名無しさん
垢版 |
2019/08/20(火) 15:36:01.76ID:aHZAynoR
>>577
実はその影響もあると思っているのですが、それだけだと前者の場合には、
命令数から言えば1〜2クロックほど速くなる場合がある程度です。
しかし、実測してみると、後者のやり方の方がもっと遅くなっている
ようなんです。

面倒ですが、マクロスイッチでコードを切り替えられるようにして
短時間の内に二つを切り替えて速度比較してみようかと思っているところです。
0580デフォルトの名無しさん
垢版 |
2019/08/20(火) 16:13:18.12ID:hCU5dYnH
テーブルがキャッシュに乗ってなかったり、
>>561と同じでテーブルがグローバル変数だと書き換えを懸念して最適化ぎ抑制されてんじゃないかな
0582デフォルトの名無しさん
垢版 |
2019/08/20(火) 16:23:55.23ID:lOKfo+mN
マクロスイッチ切り替え方式にして、ほぼ同時に両方を測定してみたら、
テーブル方式の方が速くなっていました。
0584デフォルトの名無しさん
垢版 |
2019/08/20(火) 17:25:38.94ID:lOKfo+mN
>>580
アセンブリコードを見る限り、特に問題なく、人間が単純に書いた場合
と似たようなコードになっています。

ただし、一点、テーブルの c 番目の要素を参照する際、バイト整数の c
をゼロ拡張して32BIT 整数にする必要があるのですが、自分の使ってるVC++
だと、movzx 命令を使わずに、xor eax,eax; mov al,cl のように2命令
を使ってしまっている点が、人間が最適化するより遅いコードになってしまって
います。
0585554
垢版 |
2019/08/20(火) 18:34:23.13ID:4t2XBONQ
コメントありがとうございます。

>>555
エンディアンを気にしないといけないのは後々分かりづらくなりそうですね。。

memcmpというのがあったんですね。
連続バイト比較ができてシンプルで良さそうです。
これを使ってみます。
0586デフォルトの名無しさん
垢版 |
2019/08/20(火) 19:55:32.24ID:otgnf5aI
volatile命令の他にキャッシュ命令とか無いのかよ
ルックアップテーブルをキャッシュに載せときゃ爆速じゃん
もっと言えばテーブルを石に焼いた時一番早い
0587デフォルトの名無しさん
垢版 |
2019/08/20(火) 22:55:27.89ID:C94+kmpU
>>569
>分岐予測はデータの内容関係ないやろ
分 岐 予 測 は デ ー タ の 内 容 (統計的偏り) に 関 係 あ る

>>567
最近のCPUは黒魔術で製造されているからミクロな最適化を下手に人が手を加えるより
単純なアルゴリズムにした方が速いことが多くなた
印象
■ このスレッドは過去ログ倉庫に格納されています

ニューススポーツなんでも実況