サクサク読めて、アプリ限定の機能も多数!
トップへ戻る
Pixel 9
www.kijineko.co.jp
Cの構造体のメンバ数を取得したいという要望があるようです。Cの構造体は、あくまでもコンパイル時だけの概念であり、実行時には情報が失われてしまいます。ですので、実行時にメンバ数やメンバの型、あるいはメンバ名を取得することはできません。どうしてもやりたければ、構造体とは別に自分で情報を管理するしかありません。ここまではnoocyteさんも指摘されています。 一般的な構造体が相手だと、CであれC++であれ、ここで終わりになってしまいます。しかし、後からメンバ数などの情報を取得したい構造体については、定義方法をちょっと工夫することで何とかなるかもしれません。また、実行時に取得できなくても、マクロやテンプレートを使って取得できるのであれば、それなりに使い道があるはずです。 C++のテンプレートを使って情報を取得できればよいのであれば、tupleを使えば簡単です。
株式会社きじねこは大阪のソフトウェア開発会社です。組込み系・業務系のプログラム開発から電子回路の設計までおまかせください。
処理系によってはこれでもうまくいってしまうのですが、原則としてこのようなコードには問題があります。main.cとsub.cの両方からfoo.hをインクルードしているので、変数fooの定義が重複してしまうからです。少し経験を積んだC/C++プログラマであれば、常識的なことです。 ところが、これが理解できない初心者(いや、経験1年以上なので、初心者とはいえないかもしれません)がいるのです。彼らの主張によると、「#ifndef FOO_Hのようにしているので(インクルードガードがあるので)、foo.hの内容が複数回有効になることはない」とのことです。 いろいろ話をしてみると、翻訳単位の概念がまったく理解できていないことが分かります。そうなってしまったのも無理もありません。ほぼ、Visual Studioのような統合開発環境しか使った経験がなく、あらかじめ用意された(あるいはツールが生成した)サン
複合リテラル(と可変個実引数マクロ)に関する話題が続いています。今回もその一環なのですが、どちらかといえば、どこに複合リテラルを使っているのだろうと、探さなければならないほどの脇役です。 今回のテーマは、C++のnew演算子のようなものをCで作ってみるというものです。この類のマクロは、いろいろな人が挑戦しているようですが、複合リテラルと可変個実引数マクロを組み合わせることで、なかなかよいものができそうです。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define c_new(type, ...) \ ((type*)memcpy(malloc(sizeof(type)), \ (struct{char dummy_;type init_[1];}){0,__VA_ARGS__}.init_, sizeof(typ
Account Suspended This Account Has Been Suspended
以前、「GCC拡張を使ったusing」という記事を書きました。あれから2ヶ月半ほど経ちましたが、今になって思うと、肝心なGCC拡張を忘れていたことに気付きます。"cleanup"がそれです。 "cleanup"は__attribute__で関数を指定するGCC拡張です。"cleanup"を指定した自動変数は、その生存期間が終わる時点で、指定した関数が呼び出されます。つまり、デストラクタと同じことができるわけです。 話を簡単にするために、後始末としてはfreeでメモリを解放する場合に限定して考えることにします。 #include <stdio.h> #include <stdlib.h> #include <string.h> void cleanup(void *p) { free(*(void**)p); puts(__func__); } #define using(decl) \ f
備忘録として書きとめておきます。 C++であれば、構造体をはじめとしたクラスを代入できないようにするのは簡単です。しかし、Cでも代入できない構造体を作りたくなることがときどきあります。特定の関数またはマクロを使ってコピーしないといけないようなものがそうで、そうした構造体を代入演算子を使って代入すると破綻してしまいます。そこで代入演算子で代入しようとするとコンパイルエラーにできる方法がほしいわけです。 次のように、幅0のビットフィールドをconst修飾子付きで持たせてあげると代入できなくなります。
株式会社きじねこは大阪のソフトウェア開発会社です。組込み系・業務系のプログラム開発から電子回路の設計までおまかせください。 これは、テンプレートではありませんが、offsetof マクロを用いるのが定石です。offsetof マクロは <cstddef> ヘッダで定義されますので、(組み込み用などの)自立処理系であっても、必ず提供されることが規格上保証されています(非標準処理系は別ですが)。 仮に、offsetof マクロを自作する必要がある場合、Cでは、 #define offsetof(type, member) ((size_t)&((type*)0)->member) とすれば十分でしたが、C++ではそうはいきません。なぜなら、& 演算子が多重定義されている可能性があるからで、正しく動作させるためには、 #define offsetof_(type, member) \ (rein
「標準出力」というのは、慣用的な出力を行うためのテキストストリームの結合先のことで、多くの場合、画面への表示になっています。画面といっても、Windows などで見慣れたウィンドウとかではなく、コマンドライン(Windows でいえばコマンドプロンプト)です。 しかし、プログラムの呼び出し方しだいで、標準出力は、画面への表示ではなく、ファイルや他のプログラムが操作するストリームに結合することもできます。例えば、CGI では標準出力への書き込みはブラウザへのレスポンスとなります。また別の状況では標準出力の結合先がシリアルポートになることもあるでしょう。 std::cout 標準出力に書き込むための最も一般的な方法は、std::cout を使用することです。std::cout に対して << 演算子を用いることで、
ベターCをテーマとして採り上げるからには、そもそもベターCとは何なのかを明らかにしておかなければなりません。「ベターC」というのは文字通り"より良いC"のことですが、正式な呼称でもなければ明確な定義があるわけでもありません。何をもって"より良い"とするのかも意見が分かれるところでしょう。 このように、「ベターC」というのは非常にあいまいな概念なのですが、それでも大きく分ければ次のどれかに当てはまるのではないかと思います。 C++コンパイラを使ってCとまったく同じように書くことができるスタイル Cの知識しかないプログラマでも、わずかな説明さえあれば書くことができるスタイル C++からオブジェクト指向プログラミングやジェネリックプログラミングを除外したスタイル Cの言語機能のうち、問題を起こしそうな機能の利用を制限したスタイル C++の言語機能を活用したいが結果的にできていないことを自虐的に語
久々に凶悪なマクロプログラムを作ってみました。今回のネタは、GCCの拡張機能を使ってSTLもどきを作るというものです。この類の試みはいろいろなところで行われていると思いますが、その多くはコンテナに関するものだと思います。そこで、今回はアルゴリズム関数に挑戦してみました。 といっても、初回からそんなに高機能を目指すと挫折しますので、まずは反復子として使えるのはポインタに限定することにしました。他の反復子を扱うための手法については、いずれ機会を改めて紹介できればと思います。 今回作ってみたのは、find 関数と find_if 関数です。使い方はSTLのそれとほぼ同じなので、とくに説明はいらないでしょう。Cでは等価演算子の多重定義ができないので、スカラ型以外は find_if 関数を使うことになります。ここは、(等価演算子の多重定義に代わる方法を見つけるために)無理をして頑張るより、この方針の
のようにすると、入力バッファに改行文字が残ってしまうため、直後に getchar などを呼び出すと期待した動作にならないことがあります。 これを何とか回避しようとして、fflush(stdin) を使用しているサンプルをよく見かけます。しかし、fflush 関数というのは、出力ストリーム、または直前の操作が入力ではない更新ストリームに対して使用するものであり、それ以外の場合は未定義の動作になります。 少なくとも複数の有名な処理系のマニュアルには、fflush(stdin) を入力ストリームに対して使用できる旨の記述があるため、上のように書いてもなかなか信用していただけないかもしれません。そこで、Cの標準規格から該当部分を引用したいと思います。 7.19.5.2 fflush 関数 形式 #include <stdio.h> int fflush(FILE *stream); 機能 stre
昨日書いた祝日法の改正案の件ですが、そこには「10月の大型連休」という意味不明のキーワードが出てきていました。9月なら昨年はシルバーウィークなるものがありましたが、10月は体育の日ぐらいしかないわけで、大型連休など存在しないはずです。そこで少し調査してみました。 観光庁のサイトにあった休暇分散化ワーキングチームのページを見ると、【資料3】星野委員提出資料というのがありました。そこには... ということで、なぜか国慶節(中華人民共和国の建国記念日)が出てきます。中国人観光客の誘致というだけなら(それにも反対ではありますが)まだ理解できますが、それがなぜ我が国の国民の祝日と関係があるのか、まったくの謎です。 そもそも、このワーキングチームの座長が社民党の辻元清美議員だということからして、非常に胡散臭さを感じずにはいられません。残念ながら、私にはこれ以上の分析能力はありませんが、何やら嫌な予感が
「[迷信] とりあえず memset で初期化」へのアクセスは相変わらず多いのですが、解説があっさりしているために十分意図が伝わっていないことも少なくないようです。これまでも何度か補足的な解説を行ってきたのですが、今回もその一環として、補足解説を行うことにします。 一般的な話をすると、どうしても解説が抽象的になってしまい、その結果またしても十分に意図が伝わらないということが起きそうです。そこで、今回は解説の対象を絞り込み、できるだけ具体的な話をするつもりです。今回対象とするのは「C++の構造体の初期化」です。Cの話ではありません。また、「初期化」と書いていますが、いわゆる初期化子による初期化だけでなく、最初に値を設定する意味上の初期化も対象とします。 利用者定義のコンストラクタを持つ構造体 意外に思われる方も少なくないと思いますので、最初におさらいをしておきます。構造体というのはデータメン
C/C++の入門書の学習を一通り終えた人でも、分割コンパイルについて十分に理解できていないことがよくあります。分割コンパイルを理解し、使いこなせるようにならないかぎり、C/C++でまともにプログラムを書くことも読むこともできません。しかし、分割コンパイルを解説した書籍やサイトはそう多くはありませんので、ここで徹底的に解説したいと思います。 内容的には、まずはC言語にかぎった分割コンパイルの話からはじめます。次の段階では、C++の分割コンパイルの話をします。少なくとも、まともな入門書の1冊ぐらいは理解していることを前提とします。「読み終えていること」ではなく、「理解していること」が前提です。そのレベルが怪しい人はあらかじめ復習をしておくことをお勧めします。 書籍紹介 『新版 明解C言語 入門編』 柴田望洋 [著] 『解きながら学ぶC言語』 柴田 望洋 [著], 肘井 真一 [著], 高木 宏
今回から、C/C++の分割コンパイルに関する連載を開始します。少なくとも、まともな入門書の1冊ぐらいは理解していることを前提ですので、必要なかたは入門書を復習するようにしてください。 単一のソースファイルでも書けないわけではないけれど... C/C++の入門者ないしは初級者の場合、たったひとつのソースファイルに必要なコードをすべて詰め込んでしまいがちです。そうした傾向があるというより、それ以外のやり方を知らない、あるいは分割できることを知っていてもどうすればよいか分からないのが普通です。入門者の場合はさらに、何でもかんでも main 関数に詰め込んでしまいがちです。これも傾向というよりは、関数の作り方がよく分からないことが原因のようです。 入門書の内容程度であれば、たかだか100行程度のコードでしょうから、ソースファイルを分割しなくても十分扱えますし、main 関数で全部書いても何とかなり
やろうとしていることは簡単です。標準入力から 1 文字読み込み、アルファベットの大文字であれば小文字に変換して標準出力に書き込んでいます。 ここで、アルファベットの大文字かどうかの判別には isupper を使うべきだと主張する方がおられるかもしれませんが、その主張は必ずしも正しくありません。なぜなら、isupper の挙動はその時点で設定されているロケールに依存するからです。確実に、'A'~'Z' の範囲に収まっているかどうかを判定するには、やはり自前で処理を書かなければなりません。 というわけで、isupper ではなく、自前で判定を行っていること自体は間違いではないわけですが、問題はその判定方法にあります。ASCII や ASCII と(ほぼ)互換性のある文字コードの場合、多バイト文字さえ考慮しなければ上のコードでも問題ありません。しかし、このコードには少なくとも移植性がありません。
これを迷信集に入れるべきかどうか迷ったのですが、口にこそ出さないものの、実際にこのように信じているとしか考えられないプログラマが少なからず存在することは事実です。彼らは、あたかもブロークンな英語のように、正しい文法で書こうという意思をまったく働かせることなく、デタラメなコードを書きます。そして、その背景には、「きっとコンパイラが気持ちを察してくれるに違いない」という期待が心のどこかにあるようです。 当たり前のことですが、コンパイラは単なるソフトウェアに過ぎません。できることはといえば、プログラム言語の仕様にしたがって、ソースコードを機械的に翻訳することだけです。そうしたコンパイラには、曖昧で複数の意味にとれるコードを見ただけで、それを書いたプログラマの人となりを考慮して判断することなどはできません。言葉足らずのコードを見ただけで、それを書いたプログラマが今抱えている問題を察して処理を補完し
new 式はいくつかの場合に失敗します。ひとつはメモリの割り付けに失敗した場合、もうひとつはコンストラクタによる初期化に失敗した場合です。昔の、例外処理がなかったころの C++ 処理系が、new によるメモリ割り付けに失敗した場合に空ポインタ(NULL)を返していたという歴史的経緯から、現在でもなお、new 式に失敗した場合には空ポインタが返ってくると信じているプログラマが少なくありません。 しかし実際には、new 式が空ポインタを返す状況というのはかなり限定されます。具体的には、割り付け関数 operator new が空の例外指定(throw())を持ち、かつ割り付けに失敗した場合だけです。その場合、operator new が空ポインタを返したときには、生成しようとしたクラスのコンストラクタが呼び出されることなく、new は空ポインタに評価されます。 それ以外の場合、operator
動的に割付けたメモリは自分で解放しなければならない、ファイルをオープンすれば自分でクローズしなければならない、その他獲得したリソースは自分で解放しなければならないなど、これらは必ずしも間違ってはいません。実際、C言語ではその通りです。しかし、C++に関していえば、そしてC++をあまり知らない人たちがこうした発言をする場合には、それが迷信によるものである場合が多々あります。 C++を使い慣れた方からすれば、あり得ないような誤解もあります。例えば、int 型や double 型のようなC言語にもあるような型はともかく、クラス型のオブジェクトは常に new で動的に割り付ける必要があるというものです。おそらく、Javaか何か別の言語からの類推によるものでしょう。 C++では、クラス型のオブジェクトであっても自動記憶域期間を持つことができますので、ブロックから出て生存期間を終えた時点でメモリは自動
言語を問わず、プログラミングではマジックナンバーが嫌われる傾向にあります。しかし、マジックナンバーについて誤解しているケースも少なからず見受けられます。典型的なのは、即値=マジックナンバーという誤解です。即値とマジックナンバーは同義ではありませんし、即値が常にマジックナンバーになるわけでもありません。 さすがに true や false のような即値まで全廃しろという人はそういませんが、次のような例になると微妙になってきます。 文字どおり、三角形の面積を求める関数ですが、小学校で習ったように、底辺 × 高さ ÷ 2を計算しています。ここで登場する「2」は明らかに即値ですが、これを何らかのマクロやオブジェクトに置き換えることは無意味なばかりか、かえって可読性を低下させます。三角形の面積の公式では、ここは「2」以外あり得ず、それは小学校を卒業した人なら誰でもわかることです。 一般に、自然科学の
C/C++では、汎整数型のサイズは最小表現範囲と相対的な大小関係が決まっているだけで、それ以外は処理系定義になります。char型は少なくとも8ビット以上あれば何ビットでもよく、char型のサイズが1バイトということになります。int型も16ビット以上であれば何ビットでもかまいません。このことから、char型とint型のサイズがともに16ビットとか64ビットとかでもまったくかまわないということになります。 理屈の上ではわかっていても、具体的な処理系と関わることがなければ実感がわいてきません。私の場合、もう長い間、TOPPERSプロジェクトに関わってきた関係上、JSPカーネルが対応しているテキサス・インスツルメンツ製のDSPが16ビットのchar型を持っているため、決して机上の空論ではなく、移植性に関する重要な問題であるととらえてきました。 というわけで、今回、char型とint型のサイズが同
次のページ
このページを最初にブックマークしてみませんか?
『株式会社きじねこ | 大阪のソフトウェア開発会社』の新着エントリーを見る
j次のブックマーク
k前のブックマーク
lあとで読む
eコメント一覧を開く
oページを開く