C: 在编译时或 运行 时检查变量是否具有静态存储-class 说明符

C: check at compile time or at run time that variable has static storage-class specifier

是否有可能以某种方式在编译时或 运行 时检查变量是否具有 static 存储-class 说明符?

示例:

static int v1;
int        v2;

bool r1 = is_static(v1); /* true */
bool r2 = is_static(v2); /* false */

免责声明:以下代码不符合标准、可移植,甚至不安全。请不要在生产中使用它。

我们可以通过检查变量是否在栈上来判断一个变量是否是静态的。 Out 函数 is_static() 有两个参数。第一个是指向我们要检查的变量的指针,第二个是指向堆栈开头的指针(这就是 a 的用途)。然后它使用 getrlimit() 来确定该堆栈末尾的位置并检查我们的变量是否在堆栈上。这应该适用于大多数类 unix 系统。

#include <stdio.h>
#include <sys/resource.h>

_Bool is_static(void* var, char* stack_start)
{
  struct rlimit stack; // Use getrlimit to get the maximum stack size.
  getrlimit(RLIMIT_STACK, &stack); // TODO only run this once.
  char* stack_end = stack_start - stack.rlim_cur; // Work out where the end of the stack is.
  return !((char*)var < stack_start && (char*)var > stack_end) // Return whether the variable is on the heap.
}

int main()
{
  char a = 0;

  int b = 42;
  static int c = 42;

  printf("is_static(b) returns %i\n", is_static(&b, &a));
  printf("is_static(c) returns %i\n", is_static(&c, &a));
}

我们 运行 代码并得到这个:

is_static(b) returns 0
is_static(c) returns 1

编辑:如果您不想使用 getrlimit(),那么您可以使用 __builtin_return_address() 来确定最高堆栈值。

好的,事实证明我之前的答案对静态全局变量不起作用,所以我设计了这个程序来检查全局变量是否声明为静态。它的工作方式是 dysym() 在符号 table 中找不到静态全局变量,所以我只检查它的输出。它还使用布尔值引用变量,以确保它确实存在。

#include <stdio.h>
#include <dlfcn.h>

char* a = "hello, world";
static char* b = "hello, world";

#define is_static(name) \
  (is_sym_static(#name) && &name)

_Bool is_sym_static(const char* const name)
{
  void* hdl = dlopen(NULL, 0); // TODO: optimise by only calling this once.
  return dlsym(hdl, name) == NULL;
}

int main(int argc, char** argv)
{
  printf("%i\n", is_static(a)); // prints 0
  printf("%i\n", is_static(b)); // prints 1
}

这必须用 -ldl -Wl,--export-dynamic 编译,以确保所有变量都以符号 table 结尾。这不适用于局部变量,但我们可以将其与我之前的答案结合起来......

#include <stdio.h>
#include <dlfcn.h>
#include <sys/resource.h>

static char* stack_start;

#define is_static(name) \
  (is_addr_static(&name) && is_sym_static(#name) && &name)

_Bool is_sym_static(const char* const name)
{
  void* hdl = dlopen(NULL, 0); // TODO: optimise by only calling this once.
  return dlsym(hdl, name) == NULL;
}

_Bool is_addr_static(void* var)
{
  struct rlimit stack;
  getrlimit(RLIMIT_STACK, &stack); // TODO: optimise by only calling this once.
  char* stack_end = stack_start - stack.rlim_cur;
  return !((char*)var < stack_start && (char*)var > stack_end);
}

char*        a = "hello, world";
static char* b = "hello, world";

int main(int argc, char** argv)
{
  char _;
  stack_start = &_;
  char*        c = "hello, world";
  static char* d = "hello, world";
  printf("%i\n", is_static(a)); // prints 0
  printf("%i\n", is_static(b)); // prints 1
  printf("%i\n", is_static(c)); // prints 0
  printf("%i\n", is_static(d)); // prints 1
}

现在可以检测全局和局部静态变量。然而,我认为没有理由需要这个,因为局部静态和全局静态是根本不同的东西。