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

我很确定您可以将模板元编程用于constvolatile. 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

主要是因为我想知道我是否可以:您可以通过一点内联汇编来查看寄存器中是否存在某些内容。它两次请求相同的输入,一次在寄存器中,一次在任何地方,无论是内存还是寄存器。如果更改一个更改两者,那么您将获得与两个输入相同的寄存器。

以下使用 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 扩展,这再次使其不可移植并且它是一个脆弱的 hack。您需要小心 - 积极的优化可以打破这一点。这是一个很好的提示,您应该将其留给编译器,而不是担心寄存器中有什么,并且实际使用此代码可能会改变答案的非零风险,因为它可能会占用寄存器本身!

于 2012-07-13T10:57:20.527 回答
1

实际上,您可以确定变量是否在堆中动态分配。为此,您需要跟踪malloc(), new()/new[]等返回的地址。然后您可以检查变量的地址是否落入当前分配的内存块的任何范围内。

您还可以确定变量是否为全局/静态变量。为此,您将需要让您的程序自行解析(= 解析其可执行文件)以找出相关数据部分的开始和结束位置,或者指示编译器/链接器在数据部分的开头和结尾创建全局变量。然后你看看变量的地址是否在这些变量之间的范围内。

对于const,volatileregister修饰符,您可能可以按照其他人的建议使用一些 C++“魔法”。

于 2012-07-13T09:49:42.380 回答
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 回答