2009-09-14 6 views
14

私はを極端にと非常に古い(25年!)プログラムをCからC++に変換しています。負の数で配列にアクセスする!

さまざまな整数インデックスを使用してグローバルな1次元UBYTE配列にアクセスする(非常に多くの)場所が多数あります。場合によっては、このインデックスは負の値を持つことがあります。

時々、このケースを閉じ込めて何も間違っていないことを確認しましたが、ベルトとブレースの尺度として、配列の直前にもう1つのメモリチャンクがあることを確認していました負の数の条件をトラップするために誤って省略した場合でも、配列アクセスで正解が引き出されるような適切な値があります。これは実際には長年にわたりうまく機能しました。

しかし、C++の下では、負の数で配列にアクセスするのとは異なった振る舞いをしているようですが、今はプログラムがうまく動作していないようです。処理されていない負の数の1つのケースを修正し、プログラムは正常に動作しているように見えますが、私はすべての負の数をトラップしておらず、先に問題があるかもしれないと心配しています。

私の質問は、実行時に負のインデックスを持つ配列にアクセスするインスタンスを検出する方法はありますか?誰かが答えを出すことができれば、私は感心するでしょう。あなたがかなり確信しているなら、自動化された方法でそれを行うことはできません。

私は本当にC++のプログラマーではないと付け加えておきます。今まで私がしてきたのは、C++コンパイラでプログラムをコンパイルするための絶対的な最小限度(ほとんど何もない)です。あなたの答えがファンシーな "エキスパートのみ、C++のソリューション"を含んでいる場合は、1音節の言葉で説明してください。

+0

負の値の配列にアクセスすることはできましたが、私はしませんでした! –

+0

動作する場合は、手を触れないでください。 –

+10

動作する場合は、改善してください。 –

答えて

26

グローバル1次元ubyte配列を、オーバーロードされた演算子[]を持つオブジェクトで置き換えることはできますか? int入力の絶対値を使用すると、いくつかの問題が解決する可能性があります。

編集:あなたの配列の使用パターン(ポインタは何もありません)によっては、オーバーロードされた演算子[]を持つオブジェクトを使用すると、実際には配列のユーザーには完全に透過的になる可能性があります。

+5

個人的には、絶対値を使用する代わりに例外をスローします。 (インデックスの絶対値を使用すると、多かれ少なかれランダムな値でプログラムが継続されます) – DevSolar

+0

あなたのコメントは正しい - 私は元のアプリが負のインデックスの問題は、0の周りのメモリ内の配列をミラーリングすることで、負のインデックスで絶対的な値も同様に動作するようになります。 –

+0

私は質問を理解しているので、元のバージョンのプログラムがハッキングされましたが、現在負のインデックスが発生したときに通知を受けたいので、実際にプログラムを修正することができます。行く正しい道のように聞こえる。そしてもちろん、例外も正しいでしょう(それもロギングしても、おそらくアサーションを起動すると便利かもしれません) – jalf

2

私が考えることができる唯一の方法は、インデックスをチェックするメソッドで配列をラップすることです。

4

特に、アレイを独自のページに強制することができる場合は、メモリ使用率チェックツールが動作することがあります。私はLinux上でvalgrindを使用したいと思いますが、Windows上で何を使うのかはわかりません。purify

+0

私は通常、このようなもののためにvalgrindを宣伝する最初の人ですが、最近、この問題があり、それを見つけることができませんでした。私はvalgrindの内部を知らないが、私の印象はヒープの問題を確実に捉えることだけである。 –

3

をラップします。あるいは、コンパイラが境界チェックをサポートしているかどうかを確認してください。 最悪のシナリオでは、配列に負の数で有効な値を入れません。私はをひそかにの間違いの値に置きますので、これが発生したときに明らかに間違った値が得られます。デバッガなしで問題を特定することはできませんが、少なくともコードのどこかでそれが行われているという明確な警告があります。

+0

ビジュアルスタジオ2008は境界チェックをサポートしていますか? – Mick

+0

いいえ、VSを使用したことはありませんが、そうでない場合は、Microsoftに問題があります。 –

+0

問題は、実際にインデックスをoutisde配列(!)を作成しない限り、C(と拡張子でC++)は、負のインデックスを持つ配列インデックスを確実に許可するということです。したがって、Visual C++や他のC/C++コンパイラではなく、単に境界チェックを行うことはできません。 – MSalters

1

個人的に私はあなたのインデックスのいずれかがマイナスになる可能性がある理由を整理しようとします。間違った値を返すことは明らかです。そうすれば、インデックスを負の値にしてはいけません。)

+0

1.配列のアクセスは超高速であるため、関数呼び出しですべてを永久にラップするのは嫌です。 2.負の数で配列にアクセスする方法では、(この特定のドメインで)論理的に意味をなさないので、元のドッジーな解決策が私の好きな答えになるでしょう! – Mick

+0

C++の素晴らしい点の1つは、コンパイラが非常に積極的にインライン展開していることです。すべてがコンパイラに見える限り、小さな関数*はインライン化されるので、オーバーヘッドはまったくゼロです。関数呼び出しでそれをラップすることについてあまり心配しないでください(宣言だけでなく、関数の定義がすべて表示されている限り) – jalf

+0

ところで、この情報は、誰もが見て、コメントではなく、質問に入るはずです。問題は、負の指標が修正すべき誤差であるという印象を与える。 問題のドメインで否定的なインデックスが許可されている場合は、その旨をお知らせください。それが解決策を完全に変えます。 :) – jalf

3

は道が私のために、実行時に、あるの ;

は、彼らが(いわば)ではなく、円形の穴に正方形のプラグフィット感をしようとしてより負にすることを可能にするコードを修正します負のインデックスを持つ配列 にアクセスするインスタンスを検出するには?

std::vectorでグローバルアレイを置き換えます。

vector.at(index) 

によってarray[index]構文の使用を置き換えこれは、あなたが求める正確に何が行われます。それは、ランタイム配列境界チェックを追加します。

0

あなたができることの1つは、インデックスの最小値までチェックして、そのインデックスから配列を塗りつぶすことです。

[-i] = *( - I)

ので、あなたのベースアドレスとして(-I)で始まるの代わりに、(a)のようにあなたは自分のアレイをシフトして所望の値を取得します。

6

あなたはインデックスの境界を知っていますか?

Siyfionの答えでコメントを読むと、問題のドメインで負のインデックスが許可されているように見えるため、すべてのインデックスを強制的にプラスにすることには意味がありません。より良い解決策は、言語規則を破ることなく負のインデックスを許可することです(あなたのCバージョンもbtwでした)。

したがって、あなたが行っているインデックスuseが-xからyの範囲にある場合は、単純にサイズx + yの配列を作成し、配列にアクセスするときはx番目の要素へのポインタを使用します。もちろん

int arr[10]; 
int* ptr = arr+4; 
// use ptr when you need to index into the array: 

ptr[-4]; // is valid, reads arr[0] 
ptr[5]; // is valid, reads arr[9] 

同じことができた(とすべきである)C.

にアドバイスのもう一つの作品を考えて行われています:あなたがインデックスを持つ配列が必要と仮定-4 5に例えば

、生の配列に直接アクセスしないでください。代わりに単純なアクセサ関数を定義してください。 (例えば、必ずしもそうではないが、クラスの配列を置くこともできます。あなたがクラスに入れて行う場合は、演算子をオーバーロードすることができます[]ので、それもはまだ配列のようを見ていきます)

オーバーヘッドこれは正確にゼロです(0に近い値ではなく、ゼロに近い値であることに気付かないかもしれません)。ゼロ。生成されたコードは、配列に直接アクセスした場合とまったく同じです。コンパイラは短い関数をインライン展開するので、余分なチェックを挿入して、デバッグビルドで配列の境界を越えないことを確認することもできます。

+0

シンプルでエレガントなソリューション:) –

関連する問題