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

How to get a C/C++ variable's property

本文关键字:C++ 变量 属性 何获取 获取      更新时间:2023-10-16

如何获取变量的属性?

示例:

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?

我只读过关于改变一个变量的常数的文章,但没有读过其他的。

我确信您可以为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<>

主要是因为我想知道我是否可以:你可以通过一点内联汇编来查看某个东西是否在寄存器中。它两次请求相同的输入,一次在寄存器中,一次是在存储器或寄存器的任何位置。如果更改一个会同时更改两个,那么您将获得与两个输入相同的寄存器。

以下操作使用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语句扩展,这再次使它不可移植并且是一个脆弱的破解。你需要小心——激进的优化可能会打破这种局面。这是一个很好的提示,你应该把这件事留给编译器,而不是担心寄存器中有没有什么,实际使用这段代码可能会改变答案,因为它本身可能会占用寄存器!

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

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

对于constvolatileregister修饰符,您可以按照其他人的建议使用一些C++"魔术"。

有一种相当简单的方法可以确定变量是在堆栈上(本地)还是在堆上(全局/静态/已分配)-基本上检查变量地址是否在堆栈顶部的变量和堆栈底部的变量之间。我还添加了一些测试代码。

#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;
}