1

pm次のコード行では、フィールドの 1 つでバイト単位のオフセットによってポインターを調整する必要があります。ポインタ演算がうまくいくように絶え間なく前後にキャストするよりも、これを行うためのより良い/簡単な方法はありchar *ますか?PartitionMap *

PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
    pm = (PartitionMap *)(((char *)pm) + pm->partitionMapLength);
}
return pm;

コードから理解できない人のために、から継承するバッファ内の可変長記述子をループしていますPartitionMap

また、関係者のために、 partitionMapLength は、こ​​れが実行されるシステムでサポートされている長さを常に返します。トラバースしているデータは、UDF仕様に準拠しています。

4

7 に答える 7

5

私はこれにこれらのテンプレートをよく使用します:

    template<typename T>
    T *add_pointer(T *p, unsigned int n) {
            return reinterpret_cast<T *>(reinterpret_cast<char *>(p) + n);
    }

    template<typename T>
    const T *add_pointer(const T *p, unsigned int n) {
            return reinterpret_cast<const T *>(reinterpret_cast<const char *>(p) + n);
    }

これらは型を維持しますが、たとえば次のように1バイトを追加します。

T *x = add_pointer(x, 1); // increments x by one byte, regardless of the type of x
于 2009-10-26T04:32:31.933 に答える
5

char* や intptr_t などの型にキャストしてから、最終的な型にキャストすることが唯一の方法です。

于 2009-10-26T04:09:48.673 に答える
3

もちろん、2つの変数を保持することもできます。1つchar *はバッファをステップスルーするため、もう1つはバッファPartitionMap *にアクセスするためです。何が起こっているのかを少し明確にします。

for (char *ptr = ??, pm = (PartitionMap *)ptr ; index > 0 ; --index)
{
    ptr += pm->partitionMapLength;
    pm = (PartitionMap *)ptr;
}
return pm;
于 2009-10-26T05:23:05.497 に答える
1

他の人が言ったように、キャストが必要ですが、マクロまたは関数で醜さを隠すことができます。ただし、もう 1 つ注意すべき点は、アライメントの要件です。ほとんどのプロセッサでは、型へのポインターを任意のバイト数だけインクリメントし、結果を元の型へのポインターにキャストし直すことはできません。新しいポインターを介して構造体に問題なくアクセスできます。

x86 アーキテクチャは、それを回避できる数少ないアーキテクチャの 1 つ (最も一般的なものであっても) です。ただし、Windows 用に作成している場合でも、この問題を考慮に入れる必要があります。Win64 ではアライメント要件が強制されます。

partitionMapLengthそのため、ポインターを介してメンバーにアクセスしても、プログラムがクラッシュする可能性があります。

__unalignedWindowsのようなコンパイラ拡張機能を使用して、この問題を簡単に回避できる場合があります。

PartitionMap __unaliged *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
    pm = (PartitionMap __unaligned *)(((char *)pm) + pm->partitionMapLength);
}
return pm;

または、整列されていない可能性のあるデータを適切に整列された構造体にコピーできます。

PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));

char* p = reinterpret_cast<char*>( pm);

ParititionMap tmpMap;
for ( ; index > 0 ; --index)
{

    p += pm->partitionMapLength;

    memcpy( &tmpMap, p, sizeof( newMap));
    pm = &tmpMap;
}

// you may need a more spohisticated copy to return something useful
size_t siz = pm->partitionMapLength;
pm = reinterpret_cast<PartitionMap*>( malloc( siz));
if (pm) {
    memcpy( pm, p, siz);
}
return pm;
于 2009-10-26T06:37:10.310 に答える
0

私を困惑させているのは、バイト単位で「partitionMapLength」がある理由です。

とにかくそれをキャストしたので、それが「partitionMap」ユニットにあったほうがいいのではないでしょうか?

PartitionMap *pmBase(reinterpret_cast<PartitionMap *>(partitionMaps));
PartitionMap *pm;
...
pm = pmBase + index; // just guessing about your 'index' variable here
于 2009-10-26T04:40:27.597 に答える
0

C と C++ の両方で、ポインターと を介して配列を反復処理できます++

#include <iostream>

int[] arry = { 0, 1, 2, 3 };
int* ptr = arry;
while (*ptr != 3) {
    std::cout << *ptr << '\n';
    ++ptr;
}

これを機能させるには、ポインターに追加することを定義して、ポインターに格納されているメモリアドレスを取得し、タイプが何であれ、追加される値に sizeof を掛けたものを追加します。たとえば、この例では、 に格納されているメモリ アドレスに++ptr追加します。1 * sizeof(int)ptr

型へのポインターがあり、その場所から特定のバイト数を進めたい場合、そうする唯一の方法はキャストするchar*ことです (sizeof(char)は 1 であると定義されているため)。

于 2009-10-26T06:43:25.627 に答える
0

キャストを行う必要がありますが、コードがほとんど読めなくなります。読みやすくするために、関数で分離しstatic inlineます。

于 2009-10-26T04:28:34.937 に答える