【问题标题】:C: check at compile time or at run time that variable has static storage-class specifierC:在编译时或运行时检查变量是否具有静态存储类说明符
【发布时间】:2020-12-31 12:08:09
【问题描述】:

是否有可能在编译时或运行时检查该变量是否具有 static 存储类说明符?

例子:

static int v1;
int        v2;

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

【问题讨论】:

  • 至少在运行时你不能。在编译时,IDK. (至少使用 ISO C)
  • 是的,对于符合标准的代码,编译器可以支持它作为扩展。不,没有办法在严格符合的代码中做到这一点。

标签: c static


【解决方案1】:

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

我们可以通过检查一个变量是否在栈上来判断它是否是静态的。 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() 来确定最高堆栈值。

【讨论】:

  • 有趣,谢谢!这种方法让我想起了这段代码中使用的fill()-boundlow()-studyit() 方法:homepage.divms.uiowa.edu/~jones/opsys/threads/source.txt。见thread_manager_init()
  • 顺便说一句,如果int c = 42被定义为全局非静态变量,那么is_static(&amp;c, &amp;a)返回true,这是错误的,因为c没有static存储类说明符: godbolt.org/z/rza4Y8。有什么想法吗?
  • 全局变量没有在栈上分配,所以is_static()会为全局变量返回true。全局变量和静态变量可能存储在不同的位置,并且可以在运行时区分它们,但我不确定如何区分。我猜is_stack_allocated() 会是一个更好的函数名称。
  • @chux - 恢复 Monica 有什么想法吗?
  • 我很确定这在运行时是不可能的。我查了一下,静态全局变量与非静态全局变量基本存储在同一个地方,所以我们不能可靠地检查它们的地址,编译器优化可能会移动它们。在编译时,这可能是可能的。
【解决方案2】:

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

#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 编译,以确保所有变量最终都在符号表中。这不适用于局部变量,但我们可以将它与我之前的答案结合起来......

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-17
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多