You are here:

C++/Mapping in C++

Advertisement


Question
Hello Ralph,
I've got a difficult question and I hope you know an answer or at least where to have a look at.
This is what I want to do:
I receive messages from a fieldbus (Hello Ralph,
I've got a difficult question and I hope you know an answer or at least where to have a look at.
This is what I want to do:
I receive messages from a fieldbus (CAN, but could be a random network). The message contains a data part and a unique identifier (like IP). The task receives the message and writes the data part in the Variable defined by the unique identifier. For example:
I receive a message from the network. Its unique identifier is
char* id = "MY_VAR_NAME";
Data part is double data = 3;

Now I want to assign variable MY_VAR_NAME value 3. Something like
MY_VAR_NAME = 3;
Variable MY_VAR_NAME already exists in memory space of the task. It was created by some code generated elsewhere.
What I want to is: Hope you understand it. In php it would look like this:

$MY_VAR_NAME;
$varName = "MY_VAR_NAME";
$value = 3;
eval("$".$varName."=".$value.";");

This would assign the value 3 to an already existing variable.

As you mentioned in one of your previous answers "eval" is not possible in C++, but do you know a mechanism similar to it?

I'll try an other explanation:
I've got an config file which says which network message and which variable should map. Something like:
MsgID     Destination
123       MY_VAR
ABC       ANOTHER_VAR

Everytime my task receives a message of type 123 the existing variable MY_VAR should get a new value. BUT: How do I map the string "MY_VAR"(from config file) to the memory space where my_var (the variable) is stored? Sure, I could do it by hand. But as I mentioned before: Most of the code is autogenerated. So I MUST find a generic way of doing it.
CAN but could be a random network). The message contains a data part and a unique identifier (like IP). After receiving the message I pass it to another task, which is mainly of generated code (that's why my question is so tricky: I cannot change the generated code). The new task receives the message and writes the data part in the Variable defined by the unique identifier. For example:
I receive a message from the network. Its unique identifier is char* id = "MY_VAR_NAME"; Data part is double data = 3;
Now I want to assign variable MY_VAR_NAME value 3. Something like
MY_VAR_NAME = 3;
Variable MY_VAR_NAME already exists in memory space of the task. It was created by some code generated elsewhere.
What I want to is: Hope you understand it. In php it would look like this:
$varName = "MY_VAR_NAME";
$value = 3;
eval("$".$varName."=".$value.";");
As you mentioned in one of your previous answers "eval" is not possible in C  , but do you know a mechanism similar to it?
Thx a lot in advance!!!

Answer
Your question seemed a bit garbled - several bits were repeated at random points in the questions as if you had trouble with copy and paste viz:

"I've got a difficult question and I hope you know an answer or at least where to have a look at.

This is what I want to do:

I receive messages from a fieldbus (Hello Ralph,

I've got a difficult question and I hope you know an answer or at least where to have a look at.

This is what I want to do:

I receive messages from a fieldbus (CAN, but could be a random network). The message contains a data part and a unique identifier (like IP). The task receives the message and writes the data part in the Variable defined by the unique identifier. For example:
"

And:

" before: Most of the code is autogenerated. So I MUST find a generic way of doing it.

CAN but could be a random network). The message contains a data part and a unique identifier (like IP). After receiving the message I pass it to another task, which is mainly of generated code (that's why my "

Also there is no point trying to compare to PHP for me as I have only ever looked at PHP for about 10 minutes - however I have met similar usages elsewhere!

However if I understand what you are trying to do it is something like to following:

You are receiving messages that refer to a variable by name which is a string value. You need to map this string to the actual object that represents the variable in question.

You do not state the type of the variable. In C++ this is important. A string type is different from an integer which is different from a floating point type. In fact the basic types are integer types including a char type, the floating point types and a Boolean type, pointers and references to other types and arrays of these types. A string is either an old-style C-string - which is an array of char terminated by a null character value, or is some user defined class. ISO standard C++ introduced a string type into the C++ standard library, however this is _not_ a built in type.

So in your question you were pondering mapping the string name from the message to the variable in memory. The word mapping here is quite a good thing as the standard C++ library also has a map type - in fact it is a class template for maps of key, value pairs - you look things up in the map by the key and it returns the value (assuming the map contains an entry for the given key) - in fact the C++ map returns both the key and the value.

In this case we obviously require a string type for the key but what to use for the variable type? Well that depends on what you wish to do. The simplest thing to do is to use say integers - but remember these _are_ integers and _only_ integers. I shall assume this is what you want for my examples and use the int build in type for the type of the variables you wish to store, lookup and modify.

Below is a simple solution:

   #include <map>          // for std::map
   #include <string>          // for std::string
   #include <utility>          // for std::pair, std::make_pair

   // Create short but hopefully meaningful alias for our map type
   typedef std::map<std::string, int> IntVarMap;

   //...

   // At some convenient point define object of our map type:
   IntVarMap variableMap;

   // In some function...
   variableMap.insert(std::make_pair(std::string("MY_VAR_NAME"),0));

   // Create other int varibles in a similar way...
   //...

   // In some other function...
   IntVarMap::iterator pos = variableMap.find( "MY_VAR_NAME" );
   if ( pos== variableMap.end )
   {
   // Error! Variable was not found!!!
   }
   else // Good position of variable returned, use it:
   {
       value = pos->second; // we get key,value pair returned
   }

This is the absolute bare bones of the idea. You create a map with string keys and int values. You use insert on this map to insert items (variables) into the map. These have to be inserted as key,value pairs, of type std::pair (note: all - well probably almost all -standard C++ library names are in the namespace std, hence the qualification std:: in front of names such as map, string and pair). The make_pair function template is a helper that makes a pair from the arguments provided - however it deduces the types of the objects in the pair directly from these arguments. In C++ string literals are C-style null-terminated arrays of characters, and I am using the C++ library std::string for the key, so I make sure the C-style string literal is converted to std::string by initialising a temporary std::string object a string literal having a value of the name of the variable we wish to create.

You can also look up map items using the key value with the array [] notation:

  int varValue = variableMap["MY_VAR_NAME"];

However if the name does not exist it will add it to the map and default initialise it (which should set the new int to a zero value). I shall leave it up to you to decide whether this is what you want. On the other hand it does return the value by reference which means that the values can be modified.

In reality it is probably best to wrap up the raw map into a class that holds the map as a private data member and provides just the operations required:

   class IntVariables
   {
       typedef std::map<std::string, int>       IntVarMap;

   public:
       bool Add( std::string const & var, int const & value )
       {
       // insert returns a pair containing the iterator position and
       // a bool value indicating whether the insertion was
       // successful - it fails if the map already contains an entry
       // for the key in question.
         return map_.insert( std::make_pair(var, value) ).second;
       }

       bool Get( std::string const & var, int & value ) const
       {
         IntVarMap::const_iterator pos = map_.find(var);
         bool found( pos != map_.end() );
         if ( found )
         {
         value = pos->second;
         }
         return found;
       }

       bool Set( std::string const & var, int value )
       {
         IntVarMap::iterator pos = map_.find(var);
         bool found( pos != map_.end() );
         if ( found )
         {
         pos->second = value;
         }
         return found;
       }

       void SetAndAdd( std::string const & var, int value )
       {
         map_[ var ] = value;
       }

   private:
       IntVarMap map_;
   };

The above shows the basic operations required - adding a new item, setting a new value and getting an existing value. I have shown setting a value using both find and set item found and using the [] which, as it adds if not found is wrapped in an operation called SetAndAdd. The class can be used like so:

   // In some function:

   IntVariables variables;

   bool ok(true);

   std::string varName("MY_VAR_NAME");

   ok = variables.Add(varName, 0 );

   if ( ok )
   {
       int newValue( 3 );
       variables.Set(varName, newValue );
   }

   int currentValue(0);
   if ( ok )
   {
       ok = variables.Get(varName, currentValue );
   }

   if ( ! ok )
   {
     std::cerr << "oops! Something went wrong!!\n";
   }

   std::string anotherVarName("ANOTHER_VAR_NAME");

   variables.SetAndAdd( anotherVarName, 57 );

Of course this is not too useful all in a single function, but it should be enough to give you an idea on how to split the bits up into other functions - the variable names will of course come from your messages rather than being hardcoded, etc.

If you do not wish your variables to be integers then you can change the value type of the map. If you wish your variables to store various types then you will have to either use a (3rd party) library type that can handle such things like the Boost any or variant types (see http://www.boost.org/, and http://www.boost.org/libs/libraries.htm), or write your own. I have taken this approach for simple uses in which the values are stored in a class as a string and converted to the required type on request. The use of member function templates helps in this regard as does the fact that the C++ library has support for string streams and therefore any type that supports the stream insertion and extraction operators (operator<< and operator>>) as in:

   std::cout << value; // inserts value converted to characters in std::cout
and:
   std::cin >> value;  // extract characters from std::cin,
         // convert to value's type and write to value.

can be converted to and from a std::string. Unfortunately the code to do this now belongs to a previous client and so I cannot pass it on to you. This sort of usage can be made even easier with the Boost lexical_cast (see the Boost conversion library).

If you are using C++ in anger then I suggest you obtain some decent references. For the C++ standard library I would recommend "The C++ Standard Library a Tutorial and Reference" by Nicolai M. Josuttis. I have no idea of your current programming experience in general or C++ experience in particular (other than it most likely includes some PHP) so will refrain from suggesting any other C++ texts.  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.