2016-05-13 10 views
1

私はライブラリを作成しています。このライブラリには、内部変数を初期化する関数init()があります。これらの変数は外部からアクセス可能でなければなりませんが、読み取り専用です。C言語での読み込み専用変数の取得

私は組み込みデバイスで作業しているため、実際にゲッター機能を持つのは広すぎます。

何が良い解決策は、私は(彼らは両方とも悪いソリューションと仮定)これら二つのもの以外に使用することができます:inlineゲッターを使用して

(どこ_internal_parameterstaticすることはできません):

inline int get_parameter() { extern int _interal_parameter; return _internal_parameter; } 

constを使用して(const変数は実際には保護されていません)。

// lib.c 
void init() { 
    *(int*)&parameter = get_value_for_parameter();   
} 

// lib.h 
extern const int parameter //!< initialized by init(); 
+0

最初の解決策は間違っていますか? – user4815162342

+0

ヘッダファイルを読む人は 'libc'に限定された静的変数ではないので、' _internal_parameter'をアクセスして変更することができます。 – nowox

+1

この状況では実用性が最も重要だと思います。 '_interal_parameter'への書き込みに関する適切な文書化警告とともにインラインで使用してください。とにかくユーザーがそれに書き込むと、それは自分の責任です。単一の関数呼び出しで問題が適切に機能しなくなる場合、ライブラリユーザーから少なくともあるレベルの能力を期待できます。 – user694733

答えて

2

データを非公開にする唯一の方法は、コンパイル単位で非表示にすることです。 これは、静的変数(グローバル変数の場合)を使用するか、または使用するコンパイル単位で構造体を定義するかのいずれかによって行います。

次に、値またはconst参照(constポインタを使用)のいずれかで値を返す非静的関数を宣言できます。これにより、通常の関数を作成するようになります。コンパイル単位で変数が隠されているため、インラインは役に立ちません。

関数のオーバーヘッドが高すぎる場合は、変数を非静的(または構造体を宣言する)として宣言する必要があります。このような場合、ユーザーが変数を変更するのを止めるものはありません。

変数が静的であることを宣言し、関数外に公開される変数への静的でないconstポインタを作成するのは3番目の方法かもしれません。そのような場合、ユーザは潜在的に潜在的にキャストを使用して修正することができる。

+0

あなたの後者の解決策は、私が思うものになる可能性があります:) – nowox

2

はカプセル化の良い方法がありません。

実際のカプセル化は、変数staticを作成し、それを非インラインゲッターでアクセスすることによってのみ達成できます。これは常に前記変数のコピーを返します。

2番目のバージョンは未定義の動作です。

+0

2番目のバージョンはなぜ定義されていないのですか? – nowox

+0

1.コードはコンパイルされません。定義がありません。 2.宣言と定義が一致しなければならない。あなたはconstをキャストすることはできません。 4.厳密なエイリアシング。 – Leandros

+1

「不透明型」を使用して、真のプライベートカプセル化を実現することもできます。これにより、クラスの複数のインスタンスを使用することもできます。 (不利な点は、mallocは適切に設計された組み込みシステムでは使用されていないため、クラスごとに内部メモリプールを実装する必要があるということです) – Lundin

1

実際のゲッター機能を使用するのはなぜ高価なのかは明らかではありません。コンパイラが適切にインライン展開を行っていないかのように聞こえます。また、古典的なMCUアーキテクチャーを使用していない限り、関数呼び出しオーバーヘッドの無効は非常に誇張されることがよくあります。

最適はもちろんである。また

//lib.c 
int get parameter (void) 
{ 
    return parameter; 
} 

、関数呼び出しは本当にあまりにも高価であり、あなたは、ゲッターはconst int*を返すことができインライン化を修正する方法を見つけることができない場合。呼び出し側でローカルポインタ変数を使用し、getterを一度呼び出すだけです。

intを使用していることは、組み込みシステムでは間違いです。代わりに、意味のある最小のタイプを使用してください。署名が必要ですか?「私のアプリケーションはとてもリアルタイムでクリティカルなので、関数を呼び出すことはできません」と言って、コード内にぼんやりとしたコードintをダンプすることは本当に意味がありません。

変数が真の読み取り専用変数(フラッシュメモリの定数のような)でない限り、extern constは避けるべきです。

+0

サイクルが3.75nsである266MHz CPUで作業しています。私たちの作業サイクルは10usで、アセンブリ命令はわずか2600個しかありません。関数呼び出しはパイプラインを破壊し、約14命令の遅延を引き起こします。インラインゲッターは1命令だけです。だから、本当のゲッター関数を使うのは高価です。 – nowox

+0

'int'に関する良い点。もちろん、この場合は 'int32_t'を使用しています。 – nowox

+0

@nowox 2600命令はたくさんあります!すでに自分自身を理解しているように、インラインで作業するのが最良の解決策です。 – Lundin

関連する問題