Statics [c++]

Started by
12 comments, last by discman1028 16 years, 8 months ago
Hi all. I have a few questions. ;) (1) My first is about the static keyword in C++ in the global namespace. When it is used this way, "static" has the C-meaning... the variable is only visible within the scope of the file. It provided partial OO programming in C. I have tested this in VS2005, and it seems to me that I can always #include the header I declared a static global in, and use the static variable. So, how do you actually create a situation where a static global is "hidden" in file-scope? (2) The second part of my question: For the Microsoft SDK/architecture I'm working on, declaring constant data structures as "static const" is (according to documentation) supposed to be the fastest way to initialize them. (i.e. Vector4 newVect = VECTOR4_ZERO; where the latter is a static const.) I assume they mean "static" in the "C" context. Any idea why this would make initialization any faster? (However, the static keyword is said to force the compiler to put the variables in the data segment, which makes me suspect that they meant for me to use "static" for any const member variables... i.e. NOT C-style "static". However, if that were not the case... what would making a variable C-style "static" do? Did Microsoft overload the meaning of "static" to get things to fall into the data segment on startup?) (3) Finally: Global variables have an undefined order of initialization, correct? I want to be sure I get the correct behavior:


int GetNum() { return 5; }

static int num = GetNum();






When main() is reached, num is guaranteed to be 5, correct? In what situations is is NOT ok to use num? Is the following guaranteed to be predictable? (I don't think so..)


static int num = GetNum();
static int num2 = num;






(I guess the static keyword isn't necessary for this last question... static or not, global initialization order is undefined, correct?) Thanks all.
--== discman1028 ==--
Advertisement
Quote:Original post by discman1028
(1) My first is about the static keyword in C++ in the global namespace. When it is used this way, "static" has the C-meaning... the variable is only visible within the scope of the file. It provided partial OO programming in C. I have tested this in VS2005, and it seems to me that I can always #include the header I declared a static global in, and use the static variable. So, how do you actually create a situation where a static global is "hidden" in file-scope?


Have you tried something like:

// test.hstatic int i = 0;void set(int val);void print();// test1.cpp#inclue "test.h"void set(int val) { i = val; }// test2.cpp#inclue "test.h"void print() { cout << i; }// main.cpp#include "test.h"int main(){    i = 10;    cout << i;    print();    set(20);    print();    return 0;}
Quote:Original post by janta
Quote:Original post by discman1028
(1) My first is about the static keyword in C++ in the global namespace. When it is used this way, "static" has the C-meaning... the variable is only visible within the scope of the file. It provided partial OO programming in C. I have tested this in VS2005, and it seems to me that I can always #include the header I declared a static global in, and use the static variable. So, how do you actually create a situation where a static global is "hidden" in file-scope?


Have you tried something like:

...


That's almost the exact example I tried. ;) Anyhow, I just tried that exact example. It compiles... and I just realized it DOES NOT work fine however! Thank you...

But now I am confused about the static keyword and how it's supposed to work. I had always thought that the file-scope means that it wouldn't compile. But it seems it compiles -- and only main()'s code changes and shows the variable "i" to be nonzero. Why is that? Does this mean that there are two copies of "i"... one that's modifiable, and one that's not?

[Edited by - discman1028 on July 24, 2007 7:33:44 PM]
--== discman1028 ==--
In fact by #including a file where there is a "static int i" you create a different symbol in each translation unit (all with the same name in their own unit)

Now if you try:
// test.hint i = 0;// test1.cpp#inclue "test.h"// main.cpp#include "test.h"


I think you get a "already defined" error.

Finally, if you do this:

// test.hextern int i;// test1.cpp#inclue "test.h"static int i = 0;// main.cpp#include "test.h"


I think you get an "unresolved external symbol" error because test1.cpp will hide the existence of "i" to the other units.

Does that clears things up a bit ?
Thanks for clearing that up. Though I'm still mulling it over how this helped C programmers in terms of working with the object-oriented paradigm.

Anyhow, any thoughts about (2) or (3) anyone?
--== discman1028 ==--
For number 2, if you want to define a value in a header then you have to declare it static (otherwise you'd get multiply defined symbol errors from the linker as already explained). In order for the optimizer to be able to initialize a variable using the value in the most efficient way (by embedding the value right in the code in some cases) it needs to know that the value of the 'variable' can't change (otherwise it would have to load it from memory rather than embed a literal value in the code). This is accomplished by marking it const. You need an identifier to be defined as both static and const for it to be useful as an efficient constant value for initializing other variables.

For 3, the initialization order of global variables is undefined across translation units. Within a translation unit however, variables are initialized in the order they are defined. You should avoid relying on initialization order across translation units (which means across different .cpp files in most cases).

Game Programming Blog: www.mattnewport.com/blog

Quote:Original post by discman1028
(1) My first is about the static keyword in C++ in the global namespace. When it is used this way... the variable is only visible within the scope of the file... So, how do you actually create a situation where a static global is "hidden" in file-scope?


In Cpp, the proper way to give a variable or constant file scope is to use an unnamed namespace. The keyword "static" in that context is, for all intents and purposes, deprecated. Doesn't mean it isn't still used in that way, but just because people do it doesn't make it right.

Assume you want to declare a variable in file scope. The appropriate declaration (presumably at the top of your source file) would look like:

namespace{    bool HasFileScope;} // end of unnamed namespace


Quote:Original post by discman1028
I have tested this... I can always #include the header I declared a static global in, and use the static variable.


One way to fix this is to avoid placing static variable declarations in a header file. You should strive to separate definition from implementation. If you're doing that, place the static in the appropriate source listing instead.

Oh... and I'm not sure "static global" even makes sense. If it only exists in file scope, how is it globally accessable? [wink]


Quote:Original post by discman1028
(2) The second part of my question: For the Microsoft SDK/architecture I'm working on, declaring constant data structures as "static const" is (according to documentation) supposed to be the fastest way to initialize them... I assume they mean "static" in the "C" context. Any idea why this would make initialization any faster? (However, the static keyword is said to force the compiler to put the variables in the data segment, which makes me suspect that they meant for me to use "static" for any const member variables... i.e. NOT C-style "static".


I'm fairly certain that all constants are initialized on compilation (or at very least, and probably more accurately, on linkage), hence the insertion into the data section. Think of the implementation as an extension of string pooling. If you haven't heard of it, Google it... It's important. In that sense, I'd wager the implementation is compiler dependent.

Quote:Original post by discman1028
Did Microsoft overload the meaning of "static" to get things to fall into the data segment on startup?)


I may be misunderstanding you, and if so, please ignore the following discussion of the "overloads." The meaning of the static keyword varies depending upon its usage. The three cases you'll see are:

1) The (oft misused) C standard of giving a variable file scope.
2) Within a function. In this case, the variable exists from the moment of declaration through the end of the program.
void foo( void ){    for(int i=0; i < 2; ++i)    {        // j will only be initialized once.  Once it exists, it        // exists for the life of the program.        static int j = 50;        j += i;    }    // j is inaccessable here, due to scope, but still exists.    // After first call to foo, j = 51.  On second call to foo,    // j already exists with value 51, so j's value after second     // call would be 52.}


3) Within a class. In this case, all instances of a class share the same data member.
class Bar{public:    static int foo; // static member variable foo.}int main( void ){    using std::cout;  // the usage of these assumes include of iostream    using std::endl;    Bar A, B, C;    A.foo = 0;  // really sets Bar.foo = 0    B.foo += 5; // adds 5 to Bar.foo    cout<< C.foo <<endl; // will print 5.      // Note that we haven't changed C.foo explicitly, but since     // foo is static, only one exists for all instances of Bar class.    return 0;}   


Quote:Original post by discman1028
(3) Finally: Global variables have an undefined order of initialization, correct? I want to be sure I get the correct behavior.


Again, I'm pretty sure it's compiler dependent. The rule with most initializations is to never assume a specific order. If your implementation relies heavily on the order of initialization, it's probably a design flaw. I'd also caution that the extensive use of globals usually indicates a design flaw as well, but I'm sure you'll hear that plenty. However, assuming that nothing is guaranteed about the order of global initialization, your examples (and interpretations thereof) are correct.

Quote:Original post by discman1028
I'm still mulling it over how this helped C programmers in terms of working with the object-oriented paradigm.


When it's said that the static keyword was used to simulate OOP in C, it is only meant to say that "static" introduced the concept of information hiding (limiting a variable to file scope, in this case) to C.


Hope all this helps. Cheers!
~Tim
Quote:Original post by mattnewport
For number 2, if you want to define a value in a header then you have to declare it static (otherwise you'd get multiply defined symbol errors from the linker as already explained).


This I understand... but what I usually did for my globals is use 'extern const', and define the variable in a .cpp instead.

Quote:Original post by mattnewport
Within a translation unit however, variables are initialized in the order they are defined.


This is true for sure, across all compilers? That's good to know...

Quote:Original post by twoodbur
Oh... and I'm not sure "static global" even makes sense. If it only exists in file scope, how is it globally accessable?


Well, that's why I was kind of curious as to why this was the best way to initialize constants! (because I thought static just meant file-scope only.) And I had a second problem at the same time -- I had trouble demonstrating the C-style "static" file-scoping property to myself!

Quote:Original post by twoodbur
I may be misunderstanding you, and if so, please ignore the following discussion of the "overloads." ...


I know all the definitions for "static" in C++, that is why I was thinking this may be something new... they are telling me to declare variables "static" outside of a class for the purpose of putting them in the data segment. (But I had thought that that use of "static" in that regard put things in file scope!)

Quote:Original post by twoodbur
When it's said that the static keyword was used to simulate OOP in C, it is only meant to say that "static" introduced the concept of information hiding (limiting a variable to file scope, in this case) to C.


This much I understand as well ever since I learned about that use of static... however I thought it should not compile if the static is outside of the file I want to use it from. But it seems it must be outside of the translation unit I want to use it from, for it to be hidden.

So anyhow, I guess my final big question is: How do I define static consts that I may use from anywhere? I believe janta's first example will work: the static const variable that I declare and initialize in a header file. It will create copies of itself in each translation unit that I use it in, but the copies will all have the same (const) value. (Correct me if I'm wrong.)

EDIT: Another question: Is it okay to initialize a static value with a global constant, or vice-versa? (if in separate translation units.) Is either operation defined to be consistent? Does a compiler say "ok, all globals first, then all statics!" or some such thing?

[Edited by - discman1028 on July 25, 2007 9:52:08 AM]
--== discman1028 ==--
Quote:Original post by discman1028
Hi all. I have a few questions. ;)

(1) My first is about the static keyword in C++ in the global namespace. When it is used this way, "static" has the C-meaning... the variable is only visible within the scope of the file translation unit. It provided partial OO programming in C. I have tested this in VS2005, and it seems to me that I can always #include the header I declared a static global in, and use the static variable. So, how do you actually create a situation where a static global is "hidden" in file-scope?

Meh? I corrected your first paragraph, but it seems to me that you are misundersting something: the scope of a static variable or function is the translation unit (to simplify: all the files that are compiled to produce an object file). A static variable which is declared (and defined) in a header is going to generate N different variables with the same name in N different translation unit. To have only one static variable defined, don't put the definition in a header file - put it directly in the cpp file.

More important: this has nothing to do with OO programming. I don't even understand where you get this idea. Can you elaborate please?

Quote:Original post by discman1028
(2) The second part of my question: For the Microsoft SDK/architecture I'm working on, declaring constant data structures as "static const" is (according to documentation) supposed to be the fastest way to initialize them. (i.e. Vector4 newVect = VECTOR4_ZERO; where the latter is a static const.)

I bet the guy who wrote the documentation has absolutely no clue about what he's talking about. Why would a static const be initialized faster than a const structure? That doesn't make much sense.

Quote:Original post by discman1028
I assume they mean "static" in the "C" context. Any idea why this would make initialization any faster? (However, the static keyword is said to force the compiler to put the variables in the data segment, which makes me suspect that they meant for me to use "static" for any const member variables... i.e. NOT C-style "static". However, if that were not the case... what would making a variable C-style "static" do? Did Microsoft overload the meaning of "static" to get things to fall into the data segment on startup?)

The notion of data segment is unknown to both the C standard and the C++ standard. Conclusion: this kind of information is relying on one implementation that can change in the future.

Quote:Original post by discman1028
(3) Finally: Global variables have an undefined order of initialization, correct? I want to be sure I get the correct behavior:

When main() is reached, num is guaranteed to be 5, correct? In what situations is is NOT ok to use num? Is the following guaranteed to be predictable? (I don't think so..)

*** Source Snippet Removed ***

(I guess the static keyword isn't necessary for this last question... static or not, global initialization order is undefined, correct?)

Thanks all.

This code just won the How to Enhance Unreadability Award, 2007 Edition [grin].

More seriously,
1) you should avoid global variables
2) you should avoid global variables
3) when you can't avoid global variables, try to avoid them anyway

Anyway, your first assumption is correct: num is more or less guaranteed to be 5 when you enter main() (any other behavior would break a lot of programs anyway). However, you'd better not using num as an initialization value outside main() - and especially not in other translation units. The second code snippet is a bit more problematic: num may not have been initialized before num2 is initialized. So you can get two undefined values for the price of one (although num might be initialized later).

In C++, the static keyword is never necessary (unless it's used to specify a static class member, of course). It is even far better to replace it by an anonymous namespace, which has the same effect on your code:
namespace{  int my_var; // my_var is only defined in this translation unit  void my_func() { } // same for my_func}


Regarding the questions in your latest post: I suggest you to take a rest and to explain us what you are really doing, because the solution you want to use is obviously not the right solution, whatever your problem is.

Best regards,
Thanks for the long response Emmanuel.

Quote:Original post by Emmanuel Deloget
Quote:Original post by discman1028
Hi all. I have a few questions. ;)

(1) My first is about the static keyword in C++ in the global namespace. When it is used this way, "static" has the C-meaning... the variable is only visible within the scope of the file translation unit. It provided partial OO programming in C. I have tested this in VS2005, and it seems to me that I can always #include the header I declared a static global in, and use the static variable. So, how do you actually create a situation where a static global is "hidden" in file-scope?



The file-> translation unit point was understood earlier in the post. "It provided partial OO programming in C" is what I have understood that some have used the "static" keyword for, in C.

Quote:Original post by Emmanuel Deloget
Meh? I corrected your first paragraph, but it seems to me that you are misundersting something: the scope of a static variable or function is the translation unit (to simplify: all the files that are compiled to produce an object file). A static variable which is declared (and defined) in a header is going to generate N different variables with the same name in N different translation unit. To have only one static variable defined, don't put the definition in a header file - put it directly in the cpp file.


Stated already..

Quote:Original post by Emmanuel Deloget
More important: this has nothing to do with OO programming. I don't even understand where you get this idea. Can you elaborate please?


My question is not about OO programming. I brought up OO b/c "It provided partial OO programming in C" is what I have understood that some have used the "static" keyword for, in C.

Quote:Original post by Emmanuel Deloget
Quote:Original post by discman1028
(2) The second part of my question: For the Microsoft SDK/architecture I'm working on, declaring constant data structures as "static const" is (according to documentation) supposed to be the fastest way to initialize them. (i.e. Vector4 newVect = VECTOR4_ZERO; where the latter is a static const.)

I bet the guy who wrote the documentation has absolutely no clue about what he's talking about. Why would a static const be initialized faster than a const structure? That doesn't make much sense.

Possibly. But it's MS.. I have to use the API, and try to follow the "Best Practices" advice.

Quote:Original post by Emmanuel Deloget
Quote:Original post by discman1028
I assume they mean "static" in the "C" context. Any idea why this would make initialization any faster? (However, the static keyword is said to force the compiler to put the variables in the data segment, which makes me suspect that they meant for me to use "static" for any const member variables... i.e. NOT C-style "static". However, if that were not the case... what would making a variable C-style "static" do? Did Microsoft overload the meaning of "static" to get things to fall into the data segment on startup?)

The notion of data segment is unknown to both the C standard and the C++ standard. Conclusion: this kind of information is relying on one implementation that can change in the future.


Yes. It's a very specific architecture and compiler.

Quote:Original post by Emmanuel Deloget
Quote:Original post by discman1028
(3) Finally: Global variables have an undefined order of initialization, correct? I want to be sure I get the correct behavior:

When main() is reached, num is guaranteed to be 5, correct? In what situations is is NOT ok to use num? Is the following guaranteed to be predictable? (I don't think so..)

*** Source Snippet Removed ***

(I guess the static keyword isn't necessary for this last question... static or not, global initialization order is undefined, correct?)

Thanks all.

This code just won the How to Enhance Unreadability Award, 2007 Edition [grin].

More seriously,
1) you should avoid global variables
2) you should avoid global variables
3) when you can't avoid global variables, try to avoid them anyway



Just a code sample to demonstrate the question. But, I have to live with an existing code base, so bear with me.


Quote:Original post by Emmanuel Deloget
Anyway, your first assumption is correct: num is more or less guaranteed to be 5 when you enter main() (any other behavior would break a lot of programs anyway). However, you'd better not using num as an initialization value outside main() - and especially not in other translation units. The second code snippet is a bit more problematic: num may not have been initialized before num2 is initialized. So you can get two undefined values for the price of one (although num might be initialized later).



Thanks, good to know..

Quote:Original post by Emmanuel Deloget
In C++, the static keyword is never necessary (unless it's used to specify a static class member, of course). It is even far better to replace it by an anonymous namespace, which has the same effect on your code:
namespace{  int my_var; // my_var is only defined in this translation unit  void my_func() { } // same for my_func}



The anon namespace tip was stated already... however, I am with you, in asking the question "why use the static keyword C-style in C++ code??" But that is the advice I am being given.

Quote:Original post by Emmanuel Deloget
Regarding the questions in your latest post: I suggest you to take a rest and to explain us what you are really doing, because the solution you want to use is obviously not the right solution, whatever your problem is.


Quote:
To force the compiler to put the Vector data into the data segment, you need to mark your Vector constants as static constants.

By adding the static keyword, the compiler knows to place the data into the data segment so that it can be loaded with 3 instructions, instead of regenerating the constant each time that the code is executed. By marking it as a constant, you avoid accidentally and permanently changing the values.


There's the actual quote FWIW.
--== discman1028 ==--

This topic is closed to new replies.

Advertisement