Sign in to follow this  
rastmark

Setting variable value by the name

Recommended Posts

rastmark    122
I have a variable v1 in my program. Now I want to type in the variable name and value from the command prompt, and save the value for the variable given. Like this: >SET v1 4 And the program would this: v1=4; Basically I have to do now this now: if(variableNameGiven == "v1")then v1=givenVariableValue; But is it possible, somehow, to do it like this without any if's and stuff: variableNameGiven.value = givenVariableValue; Got it?

Share this post


Link to post
Share on other sites
ToohrVyk    1596
You can do that quite easily in SH, PHP, LISP and ECMAScript, and possibly also in Python and Perl. You can do that with a small effort in .NET and Java through reflection. In C and C++, you have to do the name-variable correspondence manually.

Share this post


Link to post
Share on other sites
ToohrVyk    1596
The user writes "v1" and "lskjdf". You have to determine that "v1" is a variable (and what it corresponds to) but that "lskjdf" isn't a variable. In order to do this, you have to somehow have a list of variable names in your program.

The compiler deletes all variable names when it creates the program (although it will sometimes keep some of them in an implementation-dependent, configuration-dependent, hard-to-read-and-understand way). The closest you can get is creating a DLL which exports some functions that can be queried by name.

So, you're much better off writing these bindings by hand instead, or using an embedded Python interpreter, or using a script language instead of C++ for whatever you're doing (command-line PHP works pretty well and is fairly close to C++ in terms of syntax).

Share this post


Link to post
Share on other sites
Sneftel    1788
Not automatically. But there is almost certainly a way to do whatever it is you'd like to do. What is it you're trying to accomplish? An in-game console? A configuration file?

Share this post


Link to post
Share on other sites
ville-v    100
How about having single character as the variable name in console?


int v1, v2, v7, v11;
char v5, v6, v10;

void *array[256];
array['1'] = &v1;
array['2'] = &v2;
array['3'] = NULL; // ( I am not sure if you have to insert NULL lines or if compiler will do it for you. )
array['4'] = NULL;
array['5'] = &v5;
array['6'] = &v6;
array['7'] = &v7;
array['8'] = NULL;
array['9'] = NULL;
array['A'] = &v10;
array['B'] = &v11;

...

char symbol = user input;
some_variable value = user input;

if(!(symbol >= '1' && symbol <= '9') && !(symbol >= 'A' && symbol <= 'B')){
// Invalid name
}
else{
void *a = array[symbol];
if(a != NULL){
*a = value;
}
else{
// Invalid name again
}
}

Share this post


Link to post
Share on other sites
iMalc    2466
You can use the preprocessor to create a table mapping the string name of the variable to the address of a variable. Then you just do a lookup in that and set the value.

TABLE_START(MyMappingTable, int)
TABLE_ENTRY(v1)
TABLE_ENTRY(v2)
TABLE_ENTRY(FooBar)
TABLE_END

Then you need to write the macros TABLE_START, TABLE_ENTRY, and TABLE_END. TABLE_ENTRY must stringify the variable name as well as take the address of the variable by that name, and each table entry will contain a const char*, plus say an int*. I believe the TABLE_ENTRY marco will contain the # and/or ## operator(s) which is not something I use very often. Someone will show you how to do that.
Of course this assumes that your variables are all of the same type, e.g. int, but you can name them whatever you like. There are ways around the one-type problem as well.

Share this post


Link to post
Share on other sites
AshleysBrain    162
Quote:
Original post by Antheus
How about:
std::map<std::string, boost::any>


I would do something like that. Maybe have an array to define the initial values, eg.

struct variable_name {
std::string name;
T* ptr; // T is whatever your variable type/class is
};

variable_name variableNames[] = {
{"v1", &v1},
{"v2", &v2},
{"v3", &v3},
{"v4", &v4} // etc
};


Then you can easily write a function to dump that in to the map, and easily extend the table with new variable names if necessary. Then just look up the map to get the pointer for that name.

Share this post


Link to post
Share on other sites
rastmark    122
Thanks for everyone for the answers! It seems that to accomplish this task, many ways exist. What i'm trying to do is to have an in-game console (DirectX 9.0) where i could change my (whatever in the memory) variable values in the fly. I.e. i could type in the console: set iSpeedOfCamera 10.45 and the "system" would change the value of variable iSpeedOfCamera to 10.45 or echo an error message 'variable not found' if the variable is not found from the memory. It seems that all these methods suggested here all come down to this:

if(variable == "iThisVar") then set iThisVar = value
else if(variable == "iThatVar") then set iThatVar = value
else print error

This is not good approach when i have about 100 variables i want to modify in the fly...

Is it possible to determine - when the program is running - is there a variable named something in the memory? Are the variable names stored somewhere? Debuggers and stuff tend to know about the variable names when something crashes during the run..Hexediting?

Share this post


Link to post
Share on other sites
jyk    2094
Quote:
Original post by rastmark
Thanks for everyone for the answers! It seems that to accomplish this task, many ways exist. What i'm trying to do is to have an in-game console (DirectX 9.0) where i could change my (whatever in the memory) variable values in the fly. I.e. i could type in the console: set iSpeedOfCamera 10.45 and the "system" would change the value of variable iSpeedOfCamera to 10.45 or echo an error message 'variable not found' if the variable is not found from the memory. It seems that all these methods suggested here all come down to this:

if(variable == "iThisVar") then set iThisVar = value
else if(variable == "iThatVar") then set iThatVar = value
else print error

This is not good approach when i have about 100 variables i want to modify in the fly...

Is it possible to determine - when the program is running - is there a variable named something in the memory? Are the variable names stored somewhere? Debuggers and stuff tend to know about the variable names when something crashes during the run..Hexediting?
AFAIK, there's no portable way to directly modify specific variables (as they appear in your C++ code) by name as you describe. Nor, I would think, would you want to, since it's almost certain that you would only want a small subset of the program's variables to be modifiable from the in-game console.

Also, 100 else-if's (like in your example) are in no way required. That's what (e.g.) std::map is for.

From what I've seen, in-game consoles are usually implemented using 'manual' methods (that is, there's no automatic mapping from variable names to variables in memory). There are many ways to do this, and depending on what features you want, the system can become more or less arbitrarily complex.

If an example would be useful, take a look at the Quake 3 source (although it might take some digging to get to the console-related code).

In my own framework, I have a 'setting' class, where each setting has a name, and incorporates functionality similar to boost::any to support storing values of various types. The console interacts with these 'setting' objects, which can also be accessed from other places in the code to query or set their values. (From what I've seen at least, this approach is fairly typical.)

Share this post


Link to post
Share on other sites
Antheus    2409
Quote:
Original post by rastmark

Is it possible to determine - when the program is running - is there a variable named something in the memory? Are the variable names stored somewhere?


Not in C++.

Some compilers can emit this information, but you're never guaranteed variables are not omitted or register allocated.

Quote:
Debuggers and stuff tend to know about the variable names when something crashes during the run..Hexediting?


They use debug symbols. gcc also has a compiler switch to emit some semantic information. But neither of that is useful for any production code. And even debuggers cannot reliable interpret optimized code.

But despite this information, debugger cannot stop a program and reliably output variables beyond current "scope". It may be possible, under certain circumstances to iterate through contents of memory, but alas, that again requires knowledge of structures and how they interact. While you can manually find out the contents of std::vector (find the pointer to allocated memory, find out the type of structures stored, go to memory allocation, advance by sizeof() for the number of times stored in vector), that requires more than can be automatically provided - unless you write iteration logic yourself.

And we're back to square one.

At this point, read this. It's an all-purpose type definition for C++ that gives you all you need for reflection.

Now remember that users type in data as text strings.

So to store data into your map, use the following:
struct Property {
virtual ~Property() {};
virtual void set(const std::string &) = 0;
virtual const std::string & get() const = 0;
};

template < typename T >
struct TypedProperty : Property {
TypedProperty(T * p) : ptr(p) {}
~Property() {}
virtual void set(const std::string &s) {
// typecast from s into your variable
// this is just a fragile example
std::stringstream buf;
buf << s;
buf >> (*ptr);
}
const std::string & get() const {
std::ostringstream buf;
buf << (*ptr);
return buf.str();
}
};



Finally, if you use the previous approach to iterating the structures:

struct Visitor {
template < class T >
void visit(T & t, const char * name) {
props.insert(std::make_pair(name, new TypedProperty<T>(&t));
}
std::map<std::string, Property *> props;
};




Of course, you need to make sure the pointed-to variables or their owners are not deallocated while you're using the map, you also need to clean-up the properties you allocate and all that...

Game Programming Gems books contain at least one article I can remember off the top of my head on this topic presents a slightly different approach to getters and setters using function pointers for each.

Bottomline: You need reflection system, or something that can iterate over your variables and provide types. C++ has no such facility (at best you can get hints).

Share this post


Link to post
Share on other sites
AshleysBrain    162
Quote:
Original post by rastmark
...
It seems that all these methods suggested here all come down to this:

if(variable == "iThisVar") then set iThisVar = value
else if(variable == "iThatVar") then set iThatVar = value
else print error

This is not good approach when i have about 100 variables i want to modify in the fly...


Nonono, what I meant was to use std::map::find(). No else-ifs at all. In the example I talked about, you'd do something like:

typedef std::map<std::string, T /* your variable type */> VariablesMap;
typedef std::map<std::string, T /* your variable type */>::iterator VariablesMapIterator;

// ... in the lookup function
VariablesMapIterator i = variables_map.find(some_variable_name); // lookup entry

if (i == variables_map.end()) {
// variable name 'some_variable_name' was not found in the map, error
}
else {
// 'i' now points to a pair, i->second.ptr gives pointer to variable
// so now you can access it and set it to something :)
}


For the record, variable names basically turn in to memory addresses at compile time so they're lost. Debuggers deliberately retain this information, but not in any way you want to use for your game's variables lookup system.

Share this post


Link to post
Share on other sites
iMalc    2466
Quote:
Original post by rastmark
It seems that all these methods suggested here all come down to this:

if(variable == "iThisVar") then set iThisVar = value
else if(variable == "iThatVar") then set iThatVar = value
else print error

This is not good approach when i have about 100 variables i want to modify in the fly...

Is it possible to determine - when the program is running - is there a variable named something in the memory? Are the variable names stored somewhere? Debuggers and stuff tend to know about the variable names when something crashes during the run..Hexediting?
The approach manny of us have mentioned doesn't really come down to that. In C++ there isn't any kind of reflection like you have in .NET, so something like I've mentioned is your only option anyway.

Besides declaring a table of what variable names you're allowed to modify, you can std::sort the table during initialisation and then do the lookup in O(log n) each time using std::lower_bound. That approach is good for performance even if you have thousands of variables you want to modify on the fly! This technique works great in my own in-game binding system.

To get it any better you'd have to do it by hashing the variable names. However you don't need to add that compilcation unless it becomes a performance bottneck, and from experience you can trust me that it wont be. Hashing would probably be slower until the number of variables becomes enormous.

I can't imagine you'd want to do it without a table either. You could cause complete chaos if it were possible to modify absolutely any variable from your in-game command-line. Just think of the security implications, and the ability to crash your program too E.g. Whoops I just told it that a dynamically allocated array holds 1 billion items - hello buffer overrun crash next time it loops over that array!
You need to be able to specify which variables you want to be able to modify, and the method I've suggested would have to be about the fastest as well. It just stores pointers directly to the string literals.

[Edited by - iMalc on November 22, 2008 9:46:33 PM]

Share this post


Link to post
Share on other sites
iMalc    2466
This is a first cut. It can probably be improved or made tidier.
It could be made possible to create multiple tables holding different types, passing in the table to search as a parameter, for example.
#include <algorithm>

#define TABLE_START(name, T) struct tblEntry { const char* v; T* p; tblEntry(const char* v, T* p) : v(v), p(p) {} bool operator < (const tblEntry& rhs) const { return strcmp(v, rhs.v) < 0; } } name[] = {
#define TABLE_ENTRY(var) tblEntry(#var, &var),
#define TABLE_END(name) }; struct presorter { presorter() { std::sort(name, name + sizeof(name)/sizeof(name[0])); } } doSort;

int v1, v2, cantTouchThis, foo, bar;

TABLE_START(MyMappingTable, int)
TABLE_ENTRY(v1)
TABLE_ENTRY(v2)
TABLE_ENTRY(foo)
TABLE_ENTRY(bar)
TABLE_END(MyMappingTable)

bool SetValue(const char *v, int value)
{
tblEntry *it = std::lower_bound(MyMappingTable, MyMappingTable + sizeof(MyMappingTable)/sizeof(MyMappingTable[0]), tblEntry(v, NULL));
if (it != MyMappingTable + sizeof(MyMappingTable)/sizeof(MyMappingTable[0]) && strcmp(it->v, v) == 0)
{
// Found it, set the value
*it->p = value;
return true;
}
return false;
}

int main() {
assert(SetValue("v2", 42) == true);
assert(SetValue("cantTouchThis", 7) == false);
}









Okay, so I could have used std::pair and std::string. Just prematurely optimising here [smile].

Note that the table is sorted automatically as the app starts up. Another nice feature is that attempting to add table entried for variables that don't exist will give a compile error.

[Edited by - iMalc on November 22, 2008 9:16:29 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this