【初心者歓迎】C/C++室 Ver.102【環境依存OK】
■ このスレッドは過去ログ倉庫に格納されています
エスケープシーケンスやWin32APIなどの環境依存なものもOK そのような質問は必ず環境を書きましょう 半角空白やタブでのインデントはスレに貼ると無くなります コードを貼れる所 http://codepad.org/ https://ideone.com/ 前スレ 【初心者歓迎】C/C++室 Ver.101【環境依存OK】 https://mevius.5ch.net/test/read.cgi/tech/1500329247/ >>703 欠点なの? T ** を const T ** に勝手に変換されると困るんだが。 T * を const T * には勝手に変換するけどな >>706 ちょっと興味があるので困るコードを教えて >>705 慌ててたのかこのレス書き間違ってた func(const int * const * )にすればコンパイル通る、 T ** ==> const T * const * という変換は暗黙でok、 と書きたかった(全然違うな) >>709 int** ipp; const int ci=0; const int ** cipp; cipp = ipp; *cipp= &ci; **ipp = 3; おっと ipp の初期化忘れた int** ipp; const int ci=0; const int ** cipp; int *ip; ipp = &ip; cipp = ipp; *cipp= &ci; **ipp = 3; ロベールの本に、 ios::out | ios::trunc が意味がないと書いてあります。 既存のファイルを破棄してから書き込むということだとすると意味があるように思います。 ios::in | ios::out | ios::trunc とした場合のみ意味があると書いてあります。 どういう意味なのでしょうか? truncate は、ファイルサイズを切り詰め・縮小する。 これは、読み書き両用時に使える機能 ファイルを読み込んで、ファイルサイズを縮小して書き込む ファイルの書き込みでは、使えない。 書き込みでは、ファイルサイズ0で開くから、前のファイルが消える >>712 なるほどね。 T ** => cont T ** は許すとcont T を操作できてしまうから禁止されていて、 T * => const T * T ** => const T * const * ...(以下略) にはその問題が無いから許可されているわけか file.read((char*)buf, sizeof buf); は buf のサイズ分だけ読み込めということだと思います。 ファイルの最後の部分を読み込むとき、サイズが WIDTH 未満の場合にはどうなるのでしょうか? fstream file; file.open("hello.txt", ios::in | ios::binary); do { unsigned char buf[WIDTH]; file.read((char*)buf, sizeof buf); for (int i = 0, size = file.gcount(); i < size; ++i) { printf("%02X ", buf[i]); } cout << endl; } while (!file.eof()); file.close(); 👀 Rock54: Caution(BBR-MD5:1341adc37120578f18dba9451e6c8c3b) >>717 ありがとうございました。 あともう一つ質問させてください: ロベールの本なのですが、 int n = 0x41424344; file.write((const char*)&n, sizeof n); というコードがあるページにあります。 その少し後ろのページには、以下のコードがあります。 char buf[BUF_SIZE]; dst.write(buf, src.gcount()); ここで、なぜ dst.write((const char*)buf, src.gcount()); としていないのでしょうか? >>718 char *はconst char *に互換だから。constは書き換えないという意味で、constなしはconstありに対して互換性がある。 すみません。もう一つ質問です。 またロベールの本なんですが、以下のコードが書いてあります。 ファイルから入力中にエラーが起きたときの対処法です。 if(src.fail()) { ではなく、 if(src.fail() && ! src.eof()) { と書いてあります。その理由として、 「読み込みの場合はファイルの終端に到達した際も fail メンバ関数が 真となるため、 eof メンバ関数が真になる場合は除外しておきます。」 と書いてあります。 そこで質問です。 ファイルの終端の直前の部分を読み込む最後の読み込みの際に何等かのエラーが起こった場合、 src.fail() == true かつ src.eof() == true となります。 そのため、 src.fail() && ! src.eof() == false となってしまいます。 この場合、読み込みエラーが起こったにもかかわらず、その対処ができないことになりはしないでしょうか? それともロベールさんのコードはOKなコードなんでしょうか? fstream src; … char buf[BUF_SIZE]; src.read(buf, sizeof buf); if(src.fail() && ! src.eof()) { error = true; break; } >>720 ありがとうございます。 つまりどちらもエラーにはならないということですね。 ですが、記述が統一していない理由というのは何か考えられるでしょうか? int n = 0x41424344; file.write((const char*)&n, sizeof n); に const がついているのは、 n は int 型だから write に渡すときには絶対に キャストしなければならない。(char *) でもいいが、どうせなら const もつけて しまおうということですかね? 一方、 char buf[BUF_SIZE]; dst.write(buf, src.gcount()); の方は、キャストの必要がないからわざわざ (const char*) とキャストすることも ないかなという感じですかね? ロベールさんの本は色々細かいことが書いてあって有用なのですが、なぜこういうコードなんだろう?という 疑問を持って読んでいくと次から次へと疑問が生まれてきて読み進むのが大変です。 Cスタイルのキャストは強力すぎて、効果が分かりにくいので、モダンでは、そのキャストは、reinterpret_cast<const char *>(&n)って書いた方がいい。 winsowsにはC#コンパイラが標準付属してますが、C++コンパイラは標準付属してないんですか? つまり、その本は古い。温故知新とは言うが、Cスタイルのキャストの使用はモダンではない。 >>726 訂正。 × reinterpret_cast<const char *>(&n) ○ reinterpret_cast<char *>(&n) そのCスタイルのキャストは const_cast<const char *>(reinterpret_cast<char *>(&n))と同じ。 下手なキャストはバグのもと。キャストは最小限に。 コンパイラによっては、reinterpret_castとconst_castをCスタイルのキャストで一度にしようとすると、警告やエラーになるものもある。 file.write((const char*)&n, sizeof n); ここでconstをわざわざ付けるのは、型で書き換えないことを確認するためだが、 このCスタイルのキャストは強力すぎて、行儀が悪い。reinterpret_castとconst_castに分けるべきだと考える。 元の趣旨がキャストについての質問だけどそれは置くとして、 そういうことするなら fstream じゃなくて basic_fstream<int> を使った方がよくなくなくない? そんなもんがいいと思ってる人に何言っても無駄だし 他人に強要しなけりゃそれ使ってもいいんじゃないの >>732 初心者が入門書で学習している段階で、途中の過程をすっ飛ばしてこっちの方がいいからこれ使えなんて進めるのはかえって理解を妨げるんでないの? 繰返すが趣旨と外れてることはわかってるので、元質問は忘れて。 こっちの手段もアリだよね? っていう別の質問。 >>736 競技プログラミングが流行る前には、宿題請負スレが隆盛を誇り、私もそれに便乗していろいろやっていましたが、 競プロをやりたいとは思わないなあ… ロベールの本に以下のコードがあります。 buf という配列ですが、 for 文の中で宣言されています。 PAGE_HEIGHT 回、配列 buf が作られるのでしょうか? 何か非効率的な気がします。 for (int h = 0; h < PAGE_HEIGHT; ++h) { unsigned char buf[PAGE_WIDTH]; m_file.read((char*)buf, sizeof buf); for (int w = 0, size = m_file.gcount(); w < size; ++w) { printf("%02X ", buf[w]); } cout << endl; } スタックポインタをずらす量が変わるだけ これによる時間はゼロと思って良い >>739 そういうのを分かるようんなるにはどうすればいいのでしょうか? C++の本だけ読んでいても分からないような気がします。 もしパフォーマンスが問題になるなら printfをなんとかすべき >>740 コードを書いたときに具体的にどんな処理が行われるか を地道に学んで行くしかない アセンブラを見てもいいし本で学んでも良いし 時間を測っても良い C言語の方が簡単なのでC言語にある機能から >>738 毎ループその buf が作られるかという質問について言えば 関数に入るときに確保された領域が毎ループ使い回されるだけ >>744 ありがとうございます。 newした場合にはもちろん毎回別の領域が確保されるわけですよね。 文法だけからでは分からないことだと思うので、そのような部分を解説した本が あればよいのですが。。。 コンストラクターを起こすようなクラスならアレだけど 基本型はループの外においやらている可能性が高い まぁ使ってるコンパイラの最適化次第というのはある 文法/規格だけで解決しない自由な部分は 実際に使ってるコンパイラの吐き出すコードをみるなり 実測して違いが出るか確認いてみたり…… 初心の「それ無駄だろうという直感」は最適化で瑣末ごとになることが多い?かな? >>745 C++ スタック ヒープで検索すると解説しているページは山ほどヒットするけどいい本ってあるのかな。 CPUとメモリの動作とか簡単に学んでおくといい気がする。 スタックに収まらないような大きな領域をスタックに取ってはいけないとか 実践的に必要な知識でもあるんだよね。 >>748 個人的には、はじめて読むシリーズがコンパクトで良かった。 はじめて読む8086 はじめて読むPentium はじめて読むMASM はじめて読む486 486は結構ボリュームがある クラスの練習に文字列クラスっぽいものを作ったんですが Mystr Mystr::operator=(Mystr &obj){ //左辺に右辺を代入 return *this } こうすると代入のたびに戻り値を返すためにコピーコンストラクタとデストラクタがわざわざ呼ばれてるみたいなんですが 関数の戻り値をvoidにする以外でなくす方法はありませんか? 一応コード全文 https://ideone.com/A1iQ3Y >>750 >Mystr Mystr::operator=(Mystr &obj){ 一般的にはこうする Mystr & Mystr::operator=(Mystr &obj){ Mystr & Mystr::operator=(const Mystr &obj); ありがとうございました 戻り値にも参照が使えることを知りませんでした >>753 おそらくわかっていると思うけど、ローカル変数や テンポラリーオブジェクトの参照は返しちゃダメなので注意 ダメな例 T& f() { T a; .....; return a;} string& g() { string a, b; .....; return a+b;} >>749 はじめて読む 486 は良書だけれでも、今、これを実際のマシンで試してみることはできなくなりましたね… アセンブラって「低水準言語」なはずだけども、今となっては機械語すらもかなり高水準だもんな……。 機械語の並びをコンパイルして最適化された μop にするみたいなことが CPU の中で起こってて、 機械の気持ちを理解するには機械語はまだまだ外側の方って感じ。 >>755 動かすための情報を集約しようとしてはしてるよ。 ある程度は動く。 https://github.com/tkmc/486 アドレスでアクセスできるメモリってものがあってデータやコードが書かれてるのかー スタックなる仕組みでローカルな記憶域をほぼコストゼロで確保してんのかー と言うことがわかれば十分な気がする >>758 >>749 これの上の3冊は薄くてすぐ読めるから、もやもやとした状態でいるよりはいい気がする。 ただ、486以外は古本でしか手に入らなそうだけど。 アセンブラの前に まずは変数がどこにどのように確保されるかとか どのように初期化されるかとか そっちの方が先だろ スタティック、スタック、ヒープ をまず理解する C++であればvirtual関数が呼ばれる仕組みとかも 知ってた方が良い 例外の仕組みは機種依存が大きいのでもうちょっと先で >>761 そう。 でもスタックを理解するにはメモリという概念モデルの理解が必要 だけど皆が勧めてるようなx86の解説書はやめたほうが良いと思う セグメントレジスタとか原理を学ぶには邪魔なノイズが多過ぎる 実用レベルのCで関数ローカル変数がどう実現されてるか、となると ベースポインタというほぼ専用のレジスタが出てくるからなぁ。 そういえば昔、Cが全然分からない頃にMASMの本を読んだら、 Z80や6502のアセンブラではついぞ出てこないディレクティブが色々あって まったく意味が分からなかったのを思い出した。 高級言語のコンパイラを作ったり、ライブラリとして呼べるマシン語の サブルーチンを作るための機能なんだと後になって腑に落ちたけど。 C の言語としての理屈が現代のコンピュータの仕組みと乖離しててもはや低級言語とは言えないということを 「C は PDP-11 エミュレータ」なんて揶揄してるのをどこかで見たことがあるな。 Cに引きずられて仕様のできたMIPSはCの理解にとてもいいよ マシン語をやるのなら、実際に石を触れる感じのする環境がいいなあ、あくまで「感じ」だけれども 仮想マシンの中間コードを触るのは疑問 PCはPCで面白いし、 8bitは8bitで面白い AKI-80 の時代の人なのでラズパイで電子工作とかやってるのを見ると隔世の感がある。 Donald Knuth の MMIX っていう言語は勉強するとためになりますか? >>761 理解すると言っても何を勉強して理解するのか? という話だと思ったんだけど。 アセンブリやCPU関連の本以外で具体的に分かるものがあるというのがよく分からないな。 wikipedia の「コールスタック」の項に意外にしっかりした説明あるな コールスタックって何?スタックフレームってなに? って人は読んでおくといいと思う。 メモリとかスタックとかヒープとかって、C/C++ 言語仕様とは直接の関係がないけど、使う上では結構重要な情報だよねー。 Cを学習する上で避けられない割に、C視点側からの詳しい学習書って無いよなー。 環境依存部分だから、言語学習書に適さないってのもわかるんだが…何とかできないものかと常々思ってる。 (思ってる「だけ」で実行には移さないのだけれどもw >>772 ならないと思う。 クヌース先生の本を読む上での決まり事を、先生が定義しただけに過ぎない、と理解してる。 僕の知り合いの知り合いができたパソコン一台でお金持ちになれるやり方 役に立つかもしれません グーグルで検索するといいかも『ネットで稼ぐ方法 モニアレフヌノ』 AA6VB >>775 たしかに、そこをつく本を書けば売れるかもしれない そんな本に書くべきことは、他に何があるだろうか? ・qsort() の説明 ・アセンブリ言語とのリンク ・PEフォーマット …etc >>775 ,780 江添氏が C++ の入門書で、言語以外の周辺事情もある程度カバーしたものを書こうとしてるみたいだぞ。 今は二の補数を説明すべきかどうかとか TWITTER でグダグダ言ってるから、 当たり前みたいで、しかし説明を省略されがちなことも含まれると思う。 シフトを使って多倍長計算とか、ZDDとか(クヌースの4巻だけど日本発) 浮動小数点の誤差がらみとか、バッファオーバーフローでなんで脆弱になるのかとか、キリがなくなるぞ コンパイルとリンクとロードの話とか。 ソースファイルからオブジェクトファイルに変換したときに どんな情報が残ってどんな情報が消えるか。 オブジェクトファイル群をリンクした段階でまだ確定せずに 実行時のロードで配置されるアドレスのこと、あたり。 ちょっとCと関係ないですが、コンピュータサイエンティストの人がよくMacを使っているのはなぜですか? >>781 二の補数はあたりまえに書いてもいいとおもうけれども、二の補数以外のものがあることを陽に記述する必要はないんじゃないかな… >>785 17"でお手頃価格なWindowsなNoteが他に無くてね HPとかDELLだと2.5kgとか >>788-789 ありがとうございます。 >>789 使い勝手がいいとかそういうことはないですか? 当時は無かったな。 MSのセミナーとかもmac+windows多かったよ ヘッダーファイルについて質問なのです。 ヘッダーファイル内で、 ostream というのを使っているのですが、 #include <iostream>をヘッダーファイル内に記述していません。 エラーが出るだろうと思いつつ、ビルドしてみたらエラーが出ませんでした。 これはどういうからくりでしょうか? ヘッダファイルの中じゃなくostreamを使っている翻訳単位(cppファイル)の中で最低1回include iostreamされてればOK >>792 他のヘッダファイルで include してて間接的に読み込んでいることになってるってのが、一番ありそうかなぁ。 >>793 ありがとうございました。 ↓のファイルをビルドするとエラーが出るのですが、何が原因かよく分かりません。 フレンド関数関連だと思います。フレンド関数については全く知らないので、真似して 作っただけです。 Vec.h http://codepad.org/3ROYH1yq Vec.cpp http://codepad.org/f3eSheBS >>794 ありがとうございました。 もしかしてヘッダーファイルのみをビルドしてもオブジェクトファイルはできないんですか? >>795 ある本に書いてあるコードでは、 Vec.h と Vec.cpp のようには分かれていないため、 自分で分けたのですが、エラーになってしまいました。 定義があればヘッダだけでもオブジェクトファイルに実装はできますよ。 >>798 Vec.h http://codepad.org/3ROYH1yq 上のVec.hの最初の方の #include <iostream> #include <cassert> 削除してもビルドエラーが出ません。 プロジェクトにはVec.hしかない状態でビルドしました。 >>799 テンプレートのエラーはテンプレートが実体化するときに出ると思うよ。 だから、テンプレートを使ってないなら、エラーがあってもコンパイル自体は出来たりする。 >>800 ありがとうございました。 あともう一つ質問なのですが、ロベールの本に、 「関数を実体化するには呼び出したところからその実装が見える必要があります。」 「つまり、関数テンプレートは宣言と実装をヘッダファイルとソースファイルに分離して 書くことはできず、すべてヘッダファイルで実装する必要があるのです。」 と書いてあります。 クラステンプレートについては同様の記述がないのですが、 クラステンプレートについても宣言と実装をヘッダファイルとソースファイルに分離して 書くことはできず、すべてヘッダファイルで実装する必要がありますか? >>801 Yes。 テンプレートはヘッダファイルに書く必要がある。 同じ実体 (テンプレート引数も同じなテンプレート) はリンク時に統合されるので、 最終的な実行ファイルに複数の実体があったりはしない。 >>802 ありがとうございました。 ちょっと理解できないと思うので、あきらめて http://codepad.org/ABfo8I3a としたところビルドできました。 ありがとうございました。 ヘッダファイルについて質問です。 assert() が使いたいため、「List2.h」内に、以下のように書いたとします。 #pragma once #include "List.h" #include <cassert> 実は、「List.h」内にも#include <cassert>が書いてあります。 ヘッダファイルにはすべて#pragma onceを書いているので多重インクルードについて 問題はないと思います。 そこで質問なのですが、「List2.h」内で assert() を使っているため、自分としては、 必要ありませんが、「List2.h」内にも#include <cassert>を書いた方が分かりやす いのではないかと思いました。 既にインクルードされていてもあえて、#include <> を書くという人はいるのでしょうか? それとも、既にインクルードされていることに気付いている場合には、できるだけ #include <> は書かないほうがいいのでしょうか? ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる