-5

グローバル配列の要素としてのみ割り当てられる特定のクラスがあります(ファイルへのハンドルの例を想像してください)。

class MyClass;
MyClass A[1000];

C++ コンパイラ (g++ や clang など) をハックして、そのクラスがポインターをアドレスとしてではなくその配列内のインデックスとして発行および解釈するようにする必要があります。

つまり、インデックスを「this」ポインターとして受け入れるクラスのメソッドと、ポインターの代わりに配列内のインデックスを返すコンストラクターが必要です。

私は x86 アーキテクチャを使用して作業しているため、クラスのサイズが 1 2 4 または 8 バイトの場合、そのようなインデックスを「実効アドレス」に変換することは、アドレッシング モードの問題にすぎません。

ある種の「外部ポインタ」または同様のものを管理するために、そのような可能性がすでに存在している可能性があります。

私が知っていることは、次のように説明されている CLANG 内の機能です。

アドレス空間 #256 でポインターに注釈を付けると、X86 GS セグメント レジスタを基準にして生成されたコードになり、アドレス空間 #257 を使用すると、X86 FS セグメントを基準にします。これは非常に低レベルの機能であり、何を行っているかがわかっている場合にのみ使用する必要があることに注意してください (たとえば、OS カーネルで)。

次に例を示します。

#define GS_RELATIVE __attribute__((address_space(256)))
int foo(int GS_RELATIVE *P) {
   return *P; 
}

https://clang.llvm.org/docs/LanguageExtensions.html#memory-references-to-specified-segments

これは相対性を解決できますが、アドレスに到達するためのインデックスの乗算は解決できません。しかし、オブジェクト コンストラクターから相対アドレスを取得するためにそれを使用する方法は明確ではありません。

質問は十分に明確ではないため保留されていますが、最終的に簡単な方法を使用してとにかく解決しました。これは、同じ質問を可能な解決策として理解するのに役立つ解決策のドラフトです(最後に到着しました)。

非常に複雑な問題が「単純な」十分な方法で解決できるのは奇妙に思えます。インデックスをオブジェクトとして使用できるため、これはまさに私が必要としていたソリューションです。

// compilation using g++ on x86 with flags -O3 -m32 

// vect is the class we are acting upon
struct vect{
    int dummy_for_clarity_of_offset;
    int x;
// the "mull" method just multiplies member x with i and j
// according to the regparm(3) convention parameters up to 3 are passed in 
// registers, so the pointer to the vect structure is passed in EAX the i parameter 
// is passed in EDX and the j parameter in ECX (So the order is EAX EDX ECX )
    __attribute__ ((noinline)) __attribute__ ((regparm(3))) void mull(int i,int j){
        asm ("leal (%esi,%eax,8),%eax"); // the index in eax is converted to address
        x*=i*j;
    }
};

register vect* A asm ("%esi"); // the vect* A holds the start address of our array and                     
                              // is a register variable as it is the base of our calcs

// the same operations as above but as a function instead of method
__attribute__ ((noinline)) __attribute__ ((regparm(3))) void mull(vect& a,int i,int j)           

{
    asm ("leal (%esi,%eax,8),%eax");  
    a.x*=i*j;
}


int main(int argc, char **argv)
{
    vect* A1=new(vect[0x10]);
    A=A1;
    A[1].x=9;
    vect* p=(vect*)1; // according to "our convention" should point to A[1]
    int i0=11;int i1=21;
    mull(*p,10,20); // multiplies the member x of A[1] with 10 and 20
    p->mull(i0,i1); // multiplies the member x of A[1] with 11 and 21
}
4

2 に答える 2

1

コンパイラを変更する必要はありません。おそらく、独自のポインターのような型を使用することができます。

ArrayElement array[42];
class MyPointer{
    std::size_t index;
public:
    MyPointer(std::size_t i=0):index(i){}
    ArrayElement &operator*() const{
        return array[index];
    }
    ArrayElement *operator->() const{
        return array+index;
    }
    MyPointer &operator++(){index++;return *this}
    MyPointer operator+(std::size_t i) const{return MyPointer(index+i);}
    MyPointer &operator--(){index--;return *this}
    MyPointer operator-(std::size_t i) const{return MyPointer(index-i);}
    std::ptrdiff_t operator-(MyPointer i) const{return index-i.index;}
    // After a few years when they accept defaulted operators into c++:
    default: ==, !=, <, >, <=, >=;
    // Otherwise write your own boilerplate
};

...
MyPointer p{11};
p->asdf(); // array[11].asdf();
p-=5;
p->asdf(); // array[6].asdf();
于 2014-08-21T17:11:46.120 に答える