webmasterのブログ

[R8C][M16C] インライン関数とインラインアセンブラとテンプレートの関係

NC30のC++には、2種類のインライン関数があります。_inlineとinlineです。Cの場合には、これらは単に名前の違いだけで機能的な差異はありません。しかし、C++では全く別のものなので注意が必要です。

_inlineはCでも使える拡張機能で、ごく特殊なケースを除けば、確実にインライン置換されます。その代り、さまざまな制約があります。例えば、_inlineを使ったインライン関数内で静的オブジェクトを宣言すると、警告が出た上、翻訳単位ごとに別の実体が生成されます。また、再帰呼び出しもできなければ、関数へのポインタも取得できません。

inlineを使ったインライン関数はC++の仕様に基づきますが、デフォルトではインライン置換されません。インライン置換させるためには、-Ostatic_to_inlineおよび-Oforward_function_to_inlineオプションを付けてコンパイルする必要があります。もちろん、これらのオプションを付けたからといって、必ずインライン置換されるわけではありません。

[R8C][M16C] #pragma ADDRESSの調査

NC30には、指定したアドレスにオブジェクトを配置するための#pragma ADDRESS指令があります。これは通常、SFRにアクセスするために用いるもので、*(volatile unsigned char*)0x0052 などと書くより便利です。また、1ビットのビットフィールドにアクセスする場合には、bset などのビット命令に展開されるという強みもあります。

今回、まず初めに調査したのは、CとC++に共通した内容として、#pragma ADDRESSで使用したオブジェクトを直接使用した場合は効率のよいコードが生成されるけれども、ポインタや(C++の場合は)参照を使って間接的にアクセスした場合はどうかということです。実際試してみた結果、間接的にアクセスした場合はビット命令は生成されず、通常のオブジェクトと同じように扱われることが分かりました。

次に調査したのは、C++で#pragma ADDRESS指令を使う場合、オブジェクト名の指定はどの程度のことができるのかということです。というのは、Cであればオブジェクト名は単純な識別子で必ず表現できますが、C++の場合は、名前空間やクラス名やテンプレート引数が絡んでくるからです。

[R8C][M16C] setlocaleは誰も使わないかもしれないが...

今回もR8CおよびM16C用の純正コンパイラNC30付属の標準ライブラリの話題です。今回取り上げるのは setlocal.c です。名前からもわかるように、setlocale関数を定義しています。

このソースコードは、最初は1999年に書かれたもののようです。改訂履歴がありませんので、おそらくはCopyrightの年を変えただけで、実際のコードは何も修正されてこなかったのだろうと思います。普通なら、十数年の実績があるコードといえるわけですが、実際にはベンダも含めてまともに使った、あるいは評価した人は誰もいないのではないかと思います。

この関数の最初の部分は第一引数の正当性を評価していますが、括目してよく見ると、とんでもないバグが見えてきます。

[R8C][M16C] NC30標準ライブラリのメモリ効率

R8CおよびM16Cの純正コンパイラNC30に付属している標準ライブラリを評価しています。弊社では、M16CよりはR8Cを使う機会が多いため、ローエンドのマイコン用ライブラリとしてどうかという観点で見るように心がけています。

ローエンドのマイコン用ということであれば、実行効率よりはメモリ効率の方が重要になるケースが多いはずです。特にRAMの使用量はかなり気になります。通常、シングルチップのマイコンというのは、ROMとRAMの両方を内蔵していますが、ROMよりRAMの方が圧倒的に小さいからです。そういう意味では、NC30付属の標準ライブラリにはいろいろと荒が目立ちます。

NC30の場合、標準ライブラリのソースファイルは以下の場所に格納されています。

[C99] 第11回 その他、細部のちがい

ここでは、他の回で採り上げなかったC++とC言語の細かなちがいについて解説します。

可変個の実引数を取る関数の仮引数並び

C++では、printf 関数のような可変個の実引数を受け取る関数の仮引数並びを次のように記述することができました。

int printf(const char* format ...);  /* エラー */

しかし、C言語では、必ず ... の前にコンマを記述する必要があります。

[象の卵] new[ ] で確保した配列の要素数を取得する方法?

これを実現するには、operator new[]とoperator delete[]を定義しなおす必要があります。以下に具体例を示します。

[象の卵] 構造体/共用体のエンディアン?

この命題に取り組む前に、エンディアンの定義について確認しておくことにします。通常は、バイトオーダー、すなわちバイト単位での配置方式または配置順序のことですが、ここではnoocyteさんによる下記の定義を踏襲することにしましょう。

複数の要素 (普通はバイトまたはビット) からなるデータを表現するのに, 要素を並べる順序に自由度がある場合, 順序の選択肢の一つ一つがエンディアンである.

[象の卵] 構造体のメンバ数の取得方法?

Cの構造体のメンバ数を取得したいという要望があるようです。Cの構造体は、あくまでもコンパイル時だけの概念であり、実行時には情報が失われてしまいます。ですので、実行時にメンバ数やメンバの型、あるいはメンバ名を取得することはできません。どうしてもやりたければ、構造体とは別に自分で情報を管理するしかありません。ここまではnoocyteさんも指摘されています。

象の卵を探して...

久々にnoocyteさんのサイトにヒントを得た記事を書くことにします。今回の元ネタは象の卵です。ずいぶん前のコンテンツですが、まあ、気にせずにいきましょう。

[C99] 第10回 メモリの動的割付け

メモリの動的割付け、あるいはオブジェクトの動的生成の方法は、C++とC99では大きく異なります。

コンテンツ配信
このエントリーを含むはてなブックマーク