views:

216

answers:

5

Hello there. I've run into an interesting problem in an AI project of mine. I'm trying to format some debug text and something strange is happening. Here's a block of code:

 float ratio = 1.0f / TIME_MOD;

TIME_MOD is a static float, declared in a separate file. This value is modified based off of user input in another class (I have verified that the value is changed while still debugging within the scope of the "input" function), but whenever I try to divide by it in my outer loop I get the same number. (1 divided by the initial value of TIME_MOD).

Am I missing something regarding static variables and file scope?

+2  A: 

A static variable only exists within the current compilation unit. Remove the static from its definition and change it to "volatile" (Though this assumes you are using multiple threads, if not you needn't use volatile) and all should be fine.

Edit: By your answer here I am assuming you have some code as follows.

A.cpp:

static float TIME_MOD = <some value>;

B.CPP:

static float TIME_MOD = <some value>;

If you are doing this then TIME_MOD exists in 2 places and this is the source of your problems. You need to re-write the code more like this.

A.cpp:

float TIME_MOD = <some value>;

B.CPP (And C.CPP, D.CPP etc):

extern float TIME_MOD;

And then use TIME_MOD as usual. This tells the compiler that TIME_MOD is somewhere else and not to worry about not knowing what it contains. The linker will then go through and "link" this floating TIME_MOD definition to the correct definition.

Its also worth pointing out that it is probably work having the "extern float TIME_MOD;" in a header file somewhere and including it in any CPP files you need it in. Still keep the actual definition (ie the non extern'd definition) in one, and only one, file.

This would certainly explain the fact that I thought you were extern'ing a static (which i thought was impossible).

Goz
If I make it volatile, I get a bunch of linker errors telling me that it's already defined in the Camera.obj (the class I'm modifying the value with). One of my professors told me that one should avoid making anything except booleans volatile, but I do not remember his reasoning. Do you know why visual studio thinks that my assignment of this volatile float is a redefinition?
Rantaak
Not without seeing your code ... Are you actually externing TIME_MOD or are you simply defining it as a static in multiple compilation units and hoping that somehow they will all point to the same value?
Goz
I had a single static declaration in a single file. No calls to extern. You can't extern static data. The problem is fixed. See my answer post.
Rantaak
A: 

You could change the static variable to a #define, and set a member variable in a singleton equal to it. Modifications and accesses would apply to the singleton's member variable.

Rantaak
So .. that doesn't explain the answer. Would love to know what you were doing wrong ...
Goz
A: 

Static variables are linked internally. you can not access a static variable defined in some other source file.
The situation you are falling into may happen in case when you have defined the static variable TIME_MOD in some header file.Include the same header file in both the input and ratio source files, hence both files have a private copy of the variable TIME_MOD,
Now the input module changes the TIME_MOD value, but it modifies its own private copy so the value in ratio file remains unchanged and hence your behavior.

Now if that is the case you do not need a static TIME_MOD, and to resolve name conflicts you may like to use namespaces.

Neeraj
+4  A: 

I think there is some confusion with the word "static". We have a keyword static that does different things in different contexts and we use the word "static" to name one of three classes of "storage durations". In some contexts static does not control the storage duration of objects but only "linkage" which is probably the main reason for the confusion.


Storage durations

A storage duration is a property of an object.

  • The memory of an object with static storage duration is allocated once and once only. Initialization depends on the kind of object and where it is defined. Once it is initialized, it generally stays alive until the execution of main ends. Objects you declare and define at global/namespace scope always have a static storage duration.

  • Objects with automatic storage duration can only be defined inside a block in functions. Such an object is created when execution reaches the definition. This can happen multiple times (recursion) which creates multiple objects. When execution leaves the block the objects are automatically destroyed.

  • Dynamically allocated objects have a dynamic storage duration. In this case the user controls the life-time of the objects via new, new[], delete, delete[] etc.


Linkage

Internal vs external linkage is about visibility of names across translation units. If you declare something with external linkage you introduce a name that can be used in other translation units as well to refer to the same entity as long as those other TUs contain the proper declaration (usually contained in a header file). If you define something with internal linkage you can't access it from another translation unit by name. You can even define multiple entities with the same name (one per TU) as long as you have no more than one with external linkage.


The keyword "static"

The effect of static depends on the context:

  • If you declare or define an object at global/namespace scope it is always an object with "static storage duration". The use of the keyword static at global/namespace scope doesn't affect the storage duration at all. Instead, it affects linkage. It declares the entity -- which might be a function as well -- to have internal linkage. So, the storage class specifier has been "misused" to do something completely different: enforce internal linkage. It's sort of the opposite of extern in this context. In C++ you can achieve the same effect with an anonymous namespace. You are encouraged to prefer anonymous namespaces over static to "minimize confusion".

  • static at class scope can be used to declare objects with static storage duration in the scope of the class. There's only one such variable and not one for each object.

  • static at function scope can be used to declare objects with static storage duration that is lazily initialized


If you say "static variable" it's not clear what you mean exactly. Do you refer to the "static storage duration" or "internal linkage"?

If you want to share a "global" variable across translation units you have to declare it in a header file as an entity with external linkage and define it in exactly one translation unit. Note that the keyword static is not used:

// myheader.hpp
extern int k; // declaring an int variable with external linkage

// foo.cpp
#include "myheader.hpp"
int k;        // defining an int variable with external linkage

// bar.cpp
#include "myheader.hpp"
int main() {
    return k;
}
sellibitze
I am familiar with the class and function scope of 'static', but I have trouble understanding your first bullet point. By 'static storage duration' do you simply mean to say that the variable will not fall out of scope until the program terminates? I've used extern to get access to data such as a large, hard-coded array or a device context defined in another file. I assume that "extern int k" will allow objects within the scope of the following file to refer to "int k" which is *defined* in an included file? I like your answer. I just want to make sure I understand it entirely.
Rantaak
@Rantaak: I've added a little more content as response to your comment.
sellibitze
You need to redactor your description as it is still confusing (and I know what you are trying to say). In the bullet points only describe what the keyword does. "Static storage duration" is a separate concept to the keywords and should be described separately in its own paragraph.
Martin York
I rewrote the answer. I hope it's less confusing :)
sellibitze
@Rantaak: "static storage duration" means that it always exists, not that it is always in scope. Scope and existence are not synonymous. Do not *include* definitions, only *declarations*. Header file should not generally be instantive, just declaritive. The instantive definitions should exist in a separately compiled and linked file. And you should of course just avoid all this global data in any case.
Clifford
A: 

I guess you declared this variable in header file as: static float TIME_MOD; And included this file in cpps. By doing this you effectively created separate instances of same named variable in each compilation unit. You should change declaration to: extern float TIME_MOD; And define variable in one of cpps: float TIME_MOD = 0;

denisenkom