Solved

Macro to initialize a struct

Posted on 2001-08-27
22
629 Views
Last Modified: 2012-08-13
I need to initialize a structure using macros. Below is the structure and the macros:
struct Person
{
     int age;
     char *pName;
};

//some macs here
#define BEGIN_INIT_PERSON(VarName) \
     Person VarName = { 0,
     
#define AGE(val)    \
          val,
         
#define NAME(nam)    \
          nam

#define END_INIT_PERSON()   }; \
 
Actually, I want the macros to be more robust in the sense that if someone misses a struct field initialization, then a compiler error should be generated.
e.g., the following usage should generate a compiler error
BEGIN_INIT_PERSON(p1)
AGE(2)
END_INIT_PERSON()
in this case, the name will be assigned a garbage value.
     I tried a couple of things such as nested macros etc. But I concluded that somehow I should make the AGE and NAME macros define another macro based on VarName so that I can check it in END_INIT_PERSON so that I can generate an error using #error directive. But could  not actually get it work.
Any ideas greatly appreciated.
Thanks.
0
Comment
Question by:vbk_bgm
  • 5
  • 5
  • 3
  • +4
22 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 6428540
Why don't you use a constructor to initialize your struct, e.g.

struct Person
{
    Person ( int _age, char* _pName) {
     age = _age; pName = _pName;
    }
    int age;
    char *pName;
};

By not providing a default ctor (i.e. a ctor that takes no arguments), you'll make providing the init values mandantory...
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6428554
I agree...this is a horrible idea...

use a constructor, it is there for this very reason...
0
 
LVL 86

Expert Comment

by:jkr
ID: 6428572
>>I agree...this is a horrible idea...

Would make sense for plain C, but in C++ (as you hit the nail on the head): 'use a constructor, it is there for this very reason'
0
 
LVL 2

Author Comment

by:vbk_bgm
ID: 6428574
It's all legacy code. The macros are ther to abstract the user from the implementation details and hence provide an easy-to-use way to init the structure. the structure has many fields. Similar macros are also used in MFC (message maps).
0
 
LVL 4

Expert Comment

by:AssafLavie
ID: 6428580
Why not initialize using an aggregate initializer?

struct c{ int a, b; };

c c1 = { 1, 2 };

0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6428583
So, is it C or C++.  If it is C++, there is no excuse.

> Similar macros are also used in MFC (message maps).

That doesn't make it the right thing to do.  I doubt there is anyone out there who thinks MFC is a model piece of C++ code.
0
 
LVL 4

Expert Comment

by:AssafLavie
ID: 6428612
I agree. These macro maps are almost always a sign of poor design.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6429321
> Why not initialize using an aggregate initializer

Actually, that is what the macros are building...

-=- James.
0
 
LVL 5

Expert Comment

by:BlackDiamond
ID: 6429572
If this is really C++, you should do something like the following.  If you really still need to use the struct, just use the methods below to modify a struct instead of using the local variables.  C++ is very well suited to what you want to do (protect the implementers from themselves), but you will probably need to do a little more work up front to accomplish this, and make your legacy code compatible.  Keep in mind that macros are very prone to cause complier errors in places that you don't expect (which can be very hard to find), and are bad practice in general.  If you need Macro like definitions, try using the const keyword instead.


class Person{
   Person(){}

   void setAge(int age) {
      this->age = age;
   }
   int getAge() {
      return age;
   }
   int setName(char * pName) {
      /* Make sure the memory is allocated correctly */
      if (!this->pName || strlen(this->pName) != strlen(pName))
         if (!realloc(this->pName, strlen(pName) + 1))
            return 0;
      strncpy (this->pName, pName, strlen(pName) + 1);
      return 1;
   }
   char * getName() {
      return pName;
   }

   int isValid() {
      if ((age && pName) && (strlen(pName) > 0))
         return 1;
      else
         return 0;
   }
   private:
   int age;
   char *pName;
}

....

Person p = new Person();

p.setAge(10);
if (!p.setName("myname")) throw new whateverException();
if (!p.isvalid) throw new whateverException();
0
 
LVL 4

Expert Comment

by:AssafLavie
ID: 6429616
I don't understand what you wish to gain by using macro's to wrap the aggregate initializer.
If your goal is to allow programmers to initialize only part of the struct (or something along that line) why not use an initializer function?
Most compilers will inline this sort of routine and some of them will even do NRV optimiztion so there won't be any cost.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6429709
BlackDiamond, generally, people name the parameters differently in order to prevent clashs, and do not use "this" directly.

Also, that example:
   o does not degrade gracefully when ::realloc(...) fails
   o does not free allocated memory
   o should have getName(...) return a const pointer

-And some think that malloc/realloc/free have no real place in C++ development (except in very specific situations).  

IOW, do *not* use that code as-is in *any* project!

-=- James.
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 5

Expert Comment

by:BlackDiamond
ID: 6429983
jt,
I realize that is not good code.  I wrote it in about 3 minutes off the top of my head.  I would have used String class, but didn't wan't to confuse the issue (cause he gave all C syntax).  I simply tried to demonstrate (and hopefully this point is still there) that there are better ways to initialize, protect, and manipulate variables in C++ than structs and defines.  Thank you for pointing out some of the errors.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6430010
The comment was more for the OP than you, but thanks for explaining.

-=- James.
0
 
LVL 3

Expert Comment

by:jcgd
ID: 6430998
replace the line:
Person VarName = { 0,
with
Person VarName = {
0
 
LVL 2

Author Comment

by:vbk_bgm
ID: 6431241
That was a typo that I forgot to remove. Actually I meant Person VarName = {  instead of Person VarName = {0,
0
 
LVL 3

Expert Comment

by:jcgd
ID: 6433928
without the last '\' the macro is working well in VC6...
0
 
LVL 2

Author Comment

by:vbk_bgm
ID: 6435114
Sorry once agian. The correct macro should read as follows:
#define BEGIN_INIT_PERSON(VarName) \
     Person VarName = {  
     
#define AGE(val)    \
          val,          


#define NAME(nam)    \
          nam,

#define END_INIT_PERSON()   };

The typo does not affect the compilation since there isn't anything on the next line.
BTW, Will anyone help me in the solution?
0
 
LVL 3

Expert Comment

by:jcgd
ID: 6438766
Maybe this macro help you:

#define BEGIN_INIT_PERSON(VarName) \
    Person VarName =  
#define AGE(val)    \
          {val
#define NAME(nam)    \
               ,nam}
#define END_INIT_PERSON()   ;
0
 
LVL 2

Author Comment

by:vbk_bgm
ID: 6439169
Hi jcgd,
       I have tried that but it does not give any compilation error with the foll usuage:
BEGIN_INIT_PERSON(p1)
AGE(2)
END_INIT_PERSON()
user has missed the name macro, and it does not emit an error.
0
 
LVL 3

Expert Comment

by:jcgd
ID: 6439186
I receive an error (in VC6++), because if if don't write AGE(x) and NAME(x) no brackets are written and initialization struct without brackets it's an error compile.
0
 
LVL 3

Accepted Solution

by:
jcgd earned 100 total points
ID: 6439201
You must use the four macro to declare a complete declaration and initialization struct:
BEGIN_INIT_NAME : declare a variable of typePerson
AGE: open a bracket an assign a value to age
NAME: assign a value to name and close bracket
END_INIT_PERSON(): put end of sentence ;

0
 
LVL 2

Author Comment

by:vbk_bgm
ID: 6439218
Yes it works.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
Often, when implementing a feature, you won't know how certain events should be handled at the point where they occur and you'd rather defer to the user of your function or class. For example, a XML parser will extract a tag from the source code, wh…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now