The dangers of static variables

Started by
15 comments, last by David Neubelt 16 years, 9 months ago
If you did the following I think it would do what was expected, but then wouldn't compile because __FILE__ is replaced with a string as mentioned previously:

#define CONCAT(a,b) a##b#define MyAssert static bool CONCAT(eAssertSkipped_, CONCAT(__FILE__, __LINE__)) = false;
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
Advertisement
Quote:Original post by David Neubelt
Quote:Original post by Nathan Baum
These static variables aren't in header files. The fact that the definition of the macro that defines the static variables appears in a header file doesn't cause the static variables to exist in the header file.

If static variables are the cause of the problem, they would cause it just as well if the macro definition instead appeared directly in each source file. The problem isn't "static variables in header files" but "static variables".

According to a developer, on Microsoft's linker, I was corresponding with during this ordeal, he told me that the cost would not apply if the assert were not in a header file.

That sounds like it should be a Microsoft problem, but you said it also applied to GCC and SN (I assume you mean the tools developed by SN Systems?).

Per the standard, there is no difference between code included from a header file and the same code directly placed in the source file. Any deviation from that is therefore deviation from the standard.
Quote:Original post by David Neubelt
I can get further clarification on why it only applies for header files if you are curious why.

I would be interested to know what he says, yes.

Offhand, the only way any half-way sane linker would care about whether a macro which defined a variable was itself defined in a header is if there was some strange interaction with precompiled headers. That requires that GCC's and Microsoft's unrelated precompiled headers implementation have the same bug, which seems unlikely to me.
Quote:
Quote:A further nitpick is that "skipassert##__LINE__" won't do what you imply it does, and whilst there are workarounds to make it do what is intended, there is no way that the value of __FILE__ could ever be part of a valid variable name, since __FILE__ is replaced with a string.


We have multiple shipping products on multiple platforms and compilers with that code. I'm pretty sure it works.

On the other hand, I've just tested the exact code locally and it doesn't "do what you imply" (although it "works", for suitable values of "works").
#define Assert_(e) static bool skipassert##__LINE__##__FILE__ = false;Assert_(x == 0);

piped through the GNU C preprocessor, produces
# 1 "<stdin>"# 1 "<built-in>"# 1 "<command line>"# 1 "<stdin>"static bool skipassert__LINE____FILE__ = false;;

It's possible that Microsoft's preprocessor produces different output (although it shouldn't: GNU CPP's output is standard), but you implied that you'd tested the code on other compilers, including GCC. (That is what I was lead to understand from you saying that the problem manifested on other compiler systems.)
Quote:Original post by David Neubelt
Quote:Original post by joanusdmentia
The only way I can see this having any effect on link times is if you were doing the assert in inline functions that were getting used very frequently, in which case the linker would have to resolve those symbols to the same memory location.
Yes you are correct - I didn't relay all of the information. The cost only applies when the assert is in a header file and the function containing the assert has multiple instances of the assert.

Ah-ha. That could at least make some kind of sense. Notwithstanding possible precompiled header weirdness, the problem is still not actually that the definition appears in a header, but rather that you have identically named static variables in identically named inline functions in lots of files. Using a header makes it easier to do that, but isn't the actual cause.
Quote:Original post by David Neubelt
Quote:Original post by joanusdmentia
I corrected my post as you were writing your reply. It compiles, but try using it twice and it won't.

Hmm - you're right - I wonder how we got it to work, I need to dig up source history when I get to work and correct the original post.


__LINE__ can be fixed:

#define CONCAT3_(a,b,c) a ## b ## c#define CONCAT3(a,b,c) CONCAT3_(a,b,c)#define Assert_(e) \static bool CONCAT3(skipassert_, __LINE__, SOURCE_NAME) = false; \ if (CONCAT3(skipassert_, __LINE__, SOURCE_NAME) == false) \ // -- do assertion logic#define SOURCE_NAME FileNameCPPAssert_(x)


Ways to remove the the quotes and the period from __FILE__ are welcome.

(Note: You can use backslashes if you follow them with horizontal whitespace.)
Quote:Original post by Nathan Baum
Ways to remove the the quotes and the period from __FILE__ are welcome.


What does the __FILE__ being part of the variable name buy you? Is there some funny business with inline functions and static variables? Because, other than that, wouldn't static make the variable unique to a given function and thus to a given file?

Actually... how do inline and static variables work together?
Each instance of an inlined function reference the same static local variable (ie. each inlining doesn't get it's own version of the variable). You're right that the __FILE__ doesn't actually contribute anything to the uniqueness of the static variable.
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
Quote:Original post by Way Walker
Quote:Original post by Nathan Baum
Ways to remove the the quotes and the period from __FILE__ are welcome.

What does the __FILE__ being part of the variable name buy you?

I have no idea. I was just trying to make a working version of David's code.
Quote:
Actually... how do inline and static variables work together?

More than one definition of the same inline function can appear in a program. That means inline functions can be defined in headers. (3.2.5)

A static local variable in an inline function always refers to the same object. (7.1.2.4)
Looking over our code, I was mistaken and the static variable in our old code was simply a static flag within a do while scope. This allowed multiple copies of the flag in the same function.

It was having many copies of that variable in an inline function that caused the long link time.

-= Dave
Graphics Programmer - Ready At Dawn Studios

This topic is closed to new replies.

Advertisement