In my game I have a header file that contains properties and functions for seasons in my game. These properties are all static and include a float representing the current season and another float representing the current point in the transition between seasons, being zero if it isn't transitioning.
Several functions throughout my game rely on the transition (two at this point) and one is working perfectly. Although, in another instance this isn't working at all.
In the class responsible for controlling the background for my game, when ever the "SeasonTransition" variable is referenced it just comes up zero. But in the other class, where the variable is referenced exactly the same way, it comes up with the real value.
This is a picture after a breakpoint has been called after the game could update a few frames:
Once again these variables are declared in a c header file:
#import "somestuff.h"
static float SeasonTransition
etc...
This shouldn't be doing this right? How could I fix this?
EDIT:
The Season.h file is as follows:
//GL.h contains different functions and global variables to be used anywhere in the project.
//This file, like Season.h is a singular header file with static declarations, and is setup
//the same way. I have been developing this from the start of the project and havent had any
//problems with it.
#import "GL.h"
static float currentSeason;
static float SeasonTransition;
static void UpdateSeason(){
currentSeason += 0.0002f;
float TransitionLength = 0.15f;
float SeasonDepth = Clamp(currentSeason - floorf(currentSeason), 0, TransitionLength);
float bigTL = TransitionLength / 4;
float endTL = TransitionLength;
float Speed2 = 0;
float Speed1 = 1;
float bRatio = SeasonDepth / bigTL;
float eRatio = SeasonDepth / endTL;
SeasonTransition = (SeasonDepth < TransitionLength) ?
((SeasonDepth < bigTL) ?
(Speed1 * bRatio) + (Speed2 * (1.0f - bRatio)) :
(Speed1 * (1.0f - eRatio)) + (Speed2 * eRatio))
:
Speed2;
}
If you put static float SeasonTransition; into two separate C files (or one header file included by two separate C files), each C file will have its own independent copy of the variable.
If one of those C files then modifies the variable, it will modify its copy. It will not touch the one in the other C file. That sounds like the situation you're in.
The normal way to do this is to define the variable in one and declare it external in the other, something like:
file1.c:
int myVar; // it exists here.
file2.c:
extern int myVar; // it exists, but elsewhere.
You don't want to mark it static in the first since that effectively makes it invisible to the second. And you mark it extern in the second so that it knows the variable exists elsewhere (in the first).
You would actually see the effect if it weren't static. When the linker came to link those two files together, it would complain about having two variables with the same name.
There are many variations on how to do that, I've shown the simplest. It's probably better to have something like:
file1.h:
extern int myVar; // so everyone knows about the variable
// just by including this.
file1.c:
#include "file1.h" // or import for ObjC.
int myVar; // the actual variable.
file2.c:
#include "file1.h" // now we know about it, in the OTHER C file.
I could be wrong but I think the problem might be you don't quit understand how include/import work. These are not quit language features but preprocessor feature. When you include somewhere in a file, your say take the entire contents of that other file and stick it in here before your start compiling. So if you include the same header file in multiple different other files you will end up with multiple version of that static variable, with out the static you will get a compiler error because you have redefined the same variable multiple times. import works almost the same except if the preprocessor determines that the included file has already be include into the destination file (could be indirectly through another include), then it will not include the file again. If you understand this you can then see that declaring static variable within you header is quit strange, because you will end up with multiple versions of that variable everywhere that header is included. Normally you want to make the variable global in which case you define it in a .c or .m file and then declare it extern in the header or you want the variable to be private then you declare it static in the .c or .m file.
What static does is to hide the variable declaration from the linker, so the linker can not recognise that all the different declarations of the same name should be treated as the same variable.
#ifndef Season_h
#define Season_h
... your header stuff
#endif
Also, if you dont call updateSeason seasonTransition will be zero.
Related
I am working on a project using MSP430FR6047 and there is certain header file I need to access and change parameters previously defined.
At the moment I have to flash the MCU with modified header file every time I change the parameter but I was exploring if there is another option to do theses changes without flashing the new code, preferably by UART or some other communication protocol.
So my question is how to change these parameters during runtime? Does any one know where should I start?
Thanks
A running program cannot change its source code, supposed that you mean something like #define PARAMETER 23. You need variables instead of constants.
One primitive solution is this:
Invent a global variable per parameter, declare all of them in an extra header file and define all of them in an extra source file for better maintenance.
In the new header file undefine all parameter macros and redefine them to use the variable instead of the literals.
In the using source files, include the original header file, after that include your new header file.
Initialize the variables initially, and change parameters as you wish during run time. (Initialization could be done in the new source file.)
This solution avoids heavy editing the using source files and leaves the original header file intact.
Example:
/* original.h */
#define PARAMETER 23
int f(void); /* returns PARAMETER */
/* new.h */
#if defined(PARAMETER)
#undef PARAMETER
#define PARAMETER parameter
#endif
extern int parameter;
/* new.c */
#include "new.h" /* ensures that declarations and definitions match */
int parameter = 23;
/* original.c */
#include "original.h"
#include "new.h"
int f(void) {
return PARAMETER;
}
/* main.c */
#include <stdio.h>
#include "original.h"
#include "new.h"
int main(void) {
PARAMETER = 42;
printf("%d\n", f());
}
If you like to change the original source code, feel free to get rid of all this preprocessor stuff, and directly use variables instead of constants. But then you should re-think your design and provide parameters as arguments to existing or new functions. Global variables should be avoided, reasons are left as an exercise to you.
There are 2 cases which change parameter in header file.
Case 1: Header define default value
For example, in header file you have:
#define DEFAULT_VALUE 10
then in .c file if it is using like:
if (a < DEFAULT_VALUE)
{ /* Do something */ }
If this is the case you could update as following:
Modified the original line:
if (a < var_DefaultValue)
{ /* Do something */ }
With var_DefaultValue is global variable:
int var_DefaultValue = DEFAULT_VALUE;
By default, this will work as original.
If you want to change value, you could create a thread to receive new value somewhere and then update to var_DefaultValue.
Case 2: Header file define some precompile tag. For example:
#define DEFAULT_FEATURE 1
and in .c file you refer to feature as following:
#if DEFAULT_FEATURE
/* Do Something */
#endif
For this case, it is impossible to change it by any mean.
In the header of the class, outside of interface declaration, I've declared global constants:
NSString * const gotFilePathNotification = #"gotFilePath";
NSString * const gotResultNotification = #"gotResultOfType";
gotResultNotification is used only in this class (yet), but I reference gotFilePathNotificaion in another class implementation. To do it, I import this header.
When I try to compile, I get a duplicate symbol linker error about gotFilePathNotification in this header. Why does it happen?
You have two identifier(s) with same name across two different compilation unit(s) at file scope. This violates One Definition Rule. Instead you need to -
Declare the global variables marking to have external linkage in a header file.
extern NSString * const gotFilePathNotification;
Now provide the definition in only one source file.
NSString * const gotFilePathNotification = #"gotFilePath";
Now where ever you need to use these variables, include the header in the source file.
You need to declare them extern in the header file and define them in implementation file. See this question for clarification. Global Variables in Cocoa/Objective-C? .
The second response provides the clarification that I will reiterate here. The default storage qualifier for variables is static. This means when you try to link two different files with the same variable, as will happen when you import your header file, the linker will construe that the variable is multiply-defined.
Also make sure you're including the h file and not the m file. This was driving me nuts.
So, my current understanding of enum is that I can use it to make constants that correspond to numbers. So,
typedef enum
{
number0 = 0,
number1 = 1,
.
.
.
} Numbers;
would allow me to refer to 0 as number0 in every part of the code. This seems to work fine. However, I'm having trouble figuring out how to use this in an Xcode Project. For example, say I write one class, NumberCounter, and include this code in the header file. Then, I write another class, numberCalculator. If I want to use the same definitions in the second class, do I have to A) write the classes in the same source file, or B) include the above code in every file I want to use the numbers?
If I include the code in one class, and exclude it in the second, I get (when trying to have a function return something of type Numbers) a Parse Issue Expected a Type error, but if I include the code in both, it gives an error about 'Redefinition of enumerator'. Currently, my workaround is to include the code in every file, then use the preprocessor to make sure it is only executed once - i.e:
#ifndef NumberDef
#define NumberDef
typedef enum
{
number0 = 0,
number1 = 1,
.
.
.
} Numbers;
#endif
This works, but I feel like there should be a nice simple way of doing this. What am I missing here?
Include the header it's defined in.
XYZ.dll defines a global variable int x.
ABC.c also defines the same global variable int x.
How can one link XYZ.dll to ABC.exe? How is this conflict in global namespace resolved?
This is a really good question, and I hope it gets a real answer. From what I can gather, a "global" symbol from a dll would have to be explictly imported via an associated header file. If you have two symbols that are the same, whichever symbol gets defined last, in the c file, is the one that would take precedence. That is, if you have ABC.c, and at the top, you would import XYZ.h, and then define int x. You either clobber the int x from XYZ.h, or you get a compile time error.
The variable int x has to be declared as extern int x in the header file of XYZ . And where ever you are going to use this variable just declare this variable. Like in ABC.c in the global space declare this variable like int x;
Why do constants in all examples I've seen always start with k? And should I #define constants in header or .m file?
I'm new to Objective C, and I don't know C. Is there some tutorial somewhere that explains these sorts of things without assuming knowledge of C?
Starting constants with a "k" is a legacy of the pre-Mac OS X days. In fact, I think the practice might even come from way back in the day, when the Mac OS was written mostly in Pascal, and the predominant development language was Pascal. In C, #define'd constants are typically written in ALL CAPS, rather than prefixing with a "k".
As for where to #define constants: #define them where you're going to use them. If you expect people who #import your code to use the constants, put them in the header file; if the constants are only going to be used internally, put them in the .m file.
Current recommendations from Apple for naming constants don't include the 'k' prefix, but many organizations adopted that convention and still use it, so you still see it quite a lot.
The question of what the "k" means is answered in this question.
And if you intend for files other than that particular .m to use these constants, you have to put the constants in the header, since they can't import the .m file.
You might be interested in Cocoa Dev Central's C tutorial for Cocoa programmers. It explains a lot of the core concepts.
The k prefix comes from a time where many developers loved to use Hungarian notation in their code. In Hungarian notation, every variable has a prefix that tells you what type it is. pSize would be a pointer named "size" whereas iSize would be an integer named "size". Just looking at the name, you know the type of a variable. This can be pretty helpful in absence of modern IDEs that can show you the type of any variable at any time, otherwise you'd always have to search the declaration to know it. Following the trend of the time, Apple wanted to have a common prefix for all constants.
Okay, why not c then, like c for "constant"? Because c was already taken, in Hungarian notation, c is for "counter" (cApple means "count of apples"). There's a similar problem with the class, being a keyword in many languages, so how do you name a variable that points to a class? You will find tons of code naming this variable klass and thus k was chosen, k as in "konstant". In many languages this word actually does start with a k, see here.
Regarding your second question: You should not use #define for constant at all, if you can avoid it, as #define is typeless.
const int x = 10; // Type is int
const short y = 20; // Type is short
const uint64_t z = 30; // Type is for sure UInt64
const double d = 5000; // Type is for sure double
const char * str = "Hello"; // Type is for sure char *
#define FOO 90
What type is FOO? It's some kind of number. But what kind of number? So far any type or no type at all. Type will depend on how and where you use FOO in your code.
Also if you have a fixed set of numbers, use an enum as then the compiler can verify you are using a valid value and enum values are always constant.
If you have to use a define, it won't matter where you define it. Header files are files you share among multiple code files, so if you need the same define in more than one place, you write it into a header file and include that header file wherever that define is needed. What you write into a code file is only visible within that code file, except for non-static functions and Obj-C classes that are both globally visible by default. But unless a function is declared in a header file and that header file is included into a code file where you want to use that function, the compiler will not know how this function looks like (what parameters it expects, what result value it returns), so it cannot check any of this and must rely that you call it correctly (usually this will cause it to create a warning). Obj-C classes cannot be used at all, unless you tell the current code file at least that this name is the name of a class, yet if you want to actually do something with that class (other than just passing it around), the compiler needs to know the interface of the class, that's why interfaces go into header files (if the class is only used within the current code file, writing interface and implementation into the file is legal and will work, too).
k for "konvention". Seriously; it is just convention.
You can put a #define wherever you like; in a header, in the .m at the top, in the .m right next to where you use it. Just put it before any code that uses it.
The "intro to objective-c" documentation provided with the Xcode tool suite is actually quite good. Read it a few times (I like to re-read it once every 2 to 5 years).
However, neither it nor any of the C books that I'm aware of will answer these particular questions. The answers sort of become obvious through experience.
I believe it is because of the former prevalence of Hungarian Notation, so k was chosen because c stood for character. ( http://en.wikipedia.org/wiki/Hungarian_notation )
--Alan