如何获得C / C ++变量的属性

时间:2012-07-13 09:30:38

标签: c++ c variables scope

如何获取变量的属性?

示例:

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 个答案:

答案 0 :(得分:7)

我很确定您可以对constvolatile使用模板元编程。关于register的IDK,我非常确定您不能使用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<>

答案 1 :(得分: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语句扩展,这再次使得这个非便携式并且它是一个脆弱的黑客。你需要小心 - 积极的优化可以打破这个。这是一个非常好的提示,你应该把它留给编译器而不是担心寄存器中的内容,并且实际使用这段代码的非零风险可能会改变答案,因为它可能会占用寄存器本身!

答案 2 :(得分:1)

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

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

对于constvolatileregister修饰符,您可以使用其他人建议的某些C ++“魔法”。

答案 3 :(得分: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;
}