2

変数のプロパティを取得するにはどうすればよいですか?

例:

int a = 5;
....
....
isConstant(a); //Prints "no!" if 'a' is not a constant at this time.
isRegister(a); //Prints "yes!" if 'a' is a register at this time.important.
isVolatile(a); //Prints "trusted" if 'a' is volatile.
isLocal(a);    //If it is temporary.
isStatic(a);   //Static?

私は変数の定数の変更について読んだだけで、他のものについては読んだことがありません。

4

4 に答える 4

7

constと のテンプレート メタプログラミングを使用できると確信していますvolatile。IDKについては、ローカルスコープ変数registerを使用できないと確信しています。static

C++11 では、たとえば次のようになります。

#include <iostream>
#include <type_traits>

int main() 
{
    std::cout << boolalpha;
    std::cout << std::is_const<int>::value << '\n';
    std::cout << std::is_const<const int>::value  << '\n';
}

版画

false
true

もありますstd::is_volatile<>

于 2012-07-13T09:36:06.857 に答える
4

ほとんどの場合、できるかどうかを知りたかったからです。少しインラインアセンブリを使用して、何かがレジスタにあるかどうかを確認できます。同じ入力を 2 回要求します。1 回はレジスターで、もう 1 回はメモリーまたはレジスターのいずれかです。1 つを変更すると両方が変更される場合、両方の入力と同じレジスタが与えられています。

以下は、gcc を使用して x86 および x86_64 で機能しました。

#include <iostream>

#define isRegister(x) \
  { \
    bool result; \
    asm("notl %1; /* alter always register one */ \
         cmpl %2, %1; /* has the other changed? */ \
         sete %0; /* save to result */ \
         notl %1; /* restore */" \
        :"=&q"(result) /* out */ \
        :"r"(x), "g"(x) /* in */ \
        : /* no clobber */ \
    ); \
   std::cout << (result ? "Yes" : "No") << "\n"; \
  }

int main() {
  register int a=666;
  int b=667;
  register int c = 0;
  int d = 0;
  isRegister(a);
  isRegister(b);
  isRegister(c);
  isRegister(d);
  std::cout << a << ", " << b << ", " << c << ", " << d << "\n";
}

ここでインライン asm を使用すると、すぐに移植性がなくなります。実際のコードで gcc の expr-statement 拡張を使用すると、これも移植性がなくなり、脆弱なハックになります。注意が必要です - 積極的な最適化はこれを壊す可能性があります。これは、レジスターに何があるかどうかを心配するのではなく、これをコンパイラーに任せるべきであるという非常に良いヒントです。実際にこのコードを使用すると、レジスター自体を占有する可能性があるため、答えが変わる可能性があるゼロではないリスクがあります!

于 2012-07-13T10:57:20.527 に答える
1

変数がスタック (ローカル) にあるかヒープ (グローバル/静的/割り当て) にあるかを判断する簡単な方法があります。スタック。テストコードもいくつか追加しました。

#include <iostream>
#include <algorithm>
// we want asserts to work in release as well
#undef NDEBUG
#include <cassert>

//! Address of the first variable on the stack
void* g_stackStart;

//! \return true if the address of variable is between g_stackStart and an address of the variable on the top of the stack
template <class T>
bool isLocal(const T& var)
{
    void* stackEnd;
    __asm
    {
        mov stackEnd, ESP
    }
    // what's the direction of stack?
    if ( g_stackStart > stackEnd )
    {
        return &var < g_stackStart && &var >= stackEnd;
    }
    else
    {
        return &var >= g_stackStart && &var < stackEnd;
    }
}

// test for nested variables
void nested(int arg)
{
    int local = int();
    assert( isLocal(local) );
    assert( isLocal(arg) );
}

// global variable used for testing
int global;

int main()
{ 
    // global stack begin pointer must be set here
    __asm
    {
        mov g_stackStart, EBP
    }

    int onStack = int();
    int* onHeap = new int();
    std::pair<int, int> pair(0, 0);

    assert( isLocal(onStack) );
    assert( !isLocal(*onHeap) );
    assert( isLocal(onHeap) );
    assert( !isLocal(global) );
    assert( isLocal(pair) );
    assert( isLocal(pair.first) );
    assert( isLocal(pair.second) );
    nested(0);

    delete onHeap;

    return 0;
}
于 2012-07-13T11:41:33.957 に答える
1

実際には、変数がヒープに動的に割り当てられているかどうかを判断できます。malloc()そのためには、、new()/new[]などによって返されるアドレスを追跡する必要があります。次に、変数のアドレスが、現在割り当てられているメモリ ブロックの範囲のいずれかに該当するかどうかを確認できます。

変数がグローバル/静的変数であるかどうかを判断できる場合もあります。そのためには、プログラム自体を解析 (= 実行可能ファイルを解析) して、関連するデータ セクションの開始位置と終了位置を見つけるか、データ セクションの開始位置と終了位置にグローバル変数を作成するようコンパイラ/リンカーに指示する必要があります。次に、変数のアドレスがそれらの変数の間の範囲内にあるかどうかを確認します。

constvolatileおよび修飾子については、register他の人が提案したように、C++の「魔法」を使用できる場合があります。

于 2012-07-13T09:49:42.380 に答える