-1

私の知る限り、C/C++ のニア ポインター (またはファー ポインターではない) は、RAM 内の実際のアドレスよりも非常に小さいアドレス値を持っています。したがって、ポインター (int 型または任意のオブジェクト型ポインターなど) をインクリメントし続けると、特定の値でロールオーバーされます。さて、私の質問は次のとおりです。それが指す値をロールバックした後、有効かどうか(メモリに大きなサイズのデータ​​があると仮定します)?

これが奇妙な質問であることは承知していますが、メモリの割り当てと割り当て解除を継続的に行っている状況があります。など0x20の無効なアドレス値が原因で、特定の時点でバイナリがクラッシュすることがわかりました 。0x450x10101

この問題はポインター値のロールオーバーが原因であり、ポインターが原因でアドレスがロールオーバーされているため、無効なアドレスが表示され、アクセス時にクラッシュしているのではないかと思っていました。

私が言及している状況が、質問されているのと似ていることを願っています。違うとしても、両方の答えが知りたいです。「連続インクリメントポインター」で検索してみましたが、答えが見つかりませんでした。

編集: これは、Red Hat Linux で G++ 4.1.2 20080704 (Red Hat 4.1.2-48) でコンパイルされた新しいコードです。

実際、共有するコードは非常に大きいです。しかし、私はそれを言葉で要約することができます: 3 つのスレッドがあります:

  1. 最初のスレッド: 割り当てられた Alert クラス オブジェクトを作成し、それをキューにプッシュします。
  2. 2 番目のスレッド: キューからアラートを読み取り、処理します。
  3. 3 番目のスレッド: 20 ~ 30 分の処理後に Alert オブジェクトに割り当てられたメモリを解放します。

2 番目のスレッドによって処理される前に、3 番目のスレッドが割り当てを解除していないことを確認済みです。

しかし、アラートは定期的に (つまり、1 秒間に数千回) 生成されるため、主な質問で言及されている問題を疑っていました。私の実装での注意点: Linux パイプ キューを使用して、あるスレッドから別のスレッドにプッシュしています。そのために、送信者側からオブジェクトのアドレス値のみをプッシュし、そこでオブジェクトを削除しないようにします。これは破損の可能性のある方法ですか?以下は、この特定のタスクのコードです。

Alert* l_alert = new Alert(ADD_ACTION,
                l_vehicleType,
                l_vehicleNo,
                l_projPolyline,
                l_speed,
                l_slotId);
    m_ResultHandler->SendToWorker(&l_alert);

キュー機能の実装:

    S32 SendToWorker(queueDataType *p_instPtr)
    {
            S32 ret_val=SUCCESS;

            QueueObj.Lock();
            ret_val = QueueObj.Signal();
            QueueObj.push(*p_instPtr);
            QueueObj.UnLock();

            return ret_val;
    }

    S32 GetFromReceiver(queueDataType *p_instPtr)
    {
            QueueObj.Lock();
            while(QueueObj.size() == 0)
                    QueueObj.Wait();

            *p_instPtr = QueueObj.front();
            QueueObj.pop();
            QueueObj.UnLock();

            return SUCCESS;
    }

レシーバーエンド:

m_alertQueue->GetFromReceiver(&l_alert)
4

2 に答える 2

1

"near" ポインターと "far" ポインターの概念は、16 ビット モードの x86 のコンパイラに主に存在する概念です。 " ポインターには、ポインター自体にセグメントとオフセット値があります。32 ビットおよび 64 ビット OS では、ポインターは (一般に) フラット メモリ モデル内の単なるオフセットです (すべてのセグメントはアドレス 0 に基づいています)。

ポインターは、C 標準によれば、「単一のオブジェクトまたは要素の配列、およびその 1 つ前」を指すことができます。それ以外は、標準では未定義の動作です。このステートメントの理由の 1 つは、セグメント化されたメモリをサポートするためです。この場合、異なるセグメント間でポインタを比較するのは容易ではありません (特に、OS/2 1.x のようにセグメントが直接のベース アドレスを持たない場合はそうではありません)。 16 ビット プロテクト モードを使用したため、コードはセグメントのベース アドレスに簡単にアクセスできません.セグメントはオーバーラップする可能性があるため、ベース アドレス A + オフセット A がベース アドレス B と同じか異なるかを判断することはできません+ オフセット B)。

この基準を満たさないポインターがある場合に実際に何が起こるかは、「未定義」と述べられているとおりです。x86環境なら「クラッシュしないし、メモリを読めば何も悪くない」というのが本当の答えなのですが、もちろん「自分のもの」ではないメモリに書き込もうとすると、何か悪いことが起こる可能性があります。正確には、上書きするメモリと、そのメモリの用途によって異なります。メモリが何に使用され、どのような値が書き込まれるかを正確に知らずに、何が起こるかを正確に言うことは不可能です。

最新の 32 ビットまたは 64 ビット OS では、「無効な」メモリにアクセスすると、間違いなくプログラムがクラッシュします。これは、最新の OS には「ワイルド メモリ アクセス」を防ぐメモリ保護機能があるためです。

于 2013-09-09T10:57:38.987 に答える