Is it possible somehow to check at compile time or at run time that variable has static
storage-class specifier?
Example:
static int v1;
int v2;
bool r1 = is_static(v1); /* true */
bool r2 = is_static(v2); /* false */
Is it possible somehow to check at compile time or at run time that variable has static
storage-class specifier?
Example:
static int v1;
int v2;
bool r1 = is_static(v1); /* true */
bool r2 = is_static(v2); /* false */
Disclaimer: The following code is not standards compliant, portable, or even safe. Please don't use it in production.
We can determine whether a variable is static by checking whether it is on the stack. Out function is_static()
takes two arguments. The first is a pointer to our variable that we want to check and the second is a pointer to the beginning of the stack (that's what a
is for). It then uses getrlimit() to determine the location of the end of that stack and checks whether our variable is on the stack. This should work on most unix-like systems.
#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));
}
We run the code and get this:
is_static(b) returns 0
is_static(c) returns 1
EDIT: If you don't want to use getrlimit()
, then you could use __builtin_return_address()
to determine the highest stack value.
Ok, turns out that my previous answer didn't work for static global variables, so I have devised this program that can check whether a global variable is declared static. The way it works is that dysym() can't find static globals in the symbol table, so I just check it's output. It also references the variable with a boolean and, to ensure it actually exists.
#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
}
This must be compiled with -ldl -Wl,--export-dynamic
, to ensure that all variables end up in the symbol table. This doesn't work for local variables, but we can combine it with my previous answer and...
#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
}
This now detects both global and local static variables. I see no reason to need this however, since local static and global static are fundamentally different things.