NO

Author Topic: Variable Arugment Macros  (Read 5886 times)

Synfire

  • Guest
Variable Arugment Macros
« on: June 05, 2006, 09:25:27 PM »
I'm doing a project using C, and interestingly enough a whole lot of OOP has come into play. It's become very cumbersome to call routines like:

Code: [Select]

oTbl->Assign ( oTbl, iElement, lpszCurrent );


Especially since I have multiple objects and many of them don't warrant being defined in a global scope. Because of this, I thought I would write a simple macro:

Code: [Select]

#define OCALL(a,b,c...) a->b ( a, ## c )
/* more code */
OCALL ( oTbl, Assign, iElement, lpszCurrent );


I figured this would be fine and dandy, but it seems that PellesC doesn't like the variable macro arguments. I double checked and even noticed on the board you stated recently that PellesC has C99 on by default, am I missing something or do you have a different way of doing this?

Regards,
Bryant Keller

PS: The exact error I'm getting is error #1049: Syntax error in macro parameters.

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Variable Arugment Macros
« Reply #1 on: June 05, 2006, 11:18:52 PM »
You missed the ',' (comma) before the variable list designator (...).
Change code to:
Code: [Select]
#define OCALL(a,b,c,...) a->b ( a, ## c )
/* more code */
OCALL ( oTbl, Assign, iElement, lpszCurrent );
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

Synfire

  • Guest
Variable Arugment Macros
« Reply #2 on: June 06, 2006, 02:35:31 AM »
The recode you posted didn't work. My problem is that before using PellesC I was prone to use GNU-C which uses the variable argument handling like posted above (named), I am aware many compilers do this differently, some compilers I've seen use:

Code: [Select]
#define OCALL(a,b,...) a->b ( a, ## __VA_ARGS__ )

But alas this didn't work either. (even though IIRC this is the "proper" way to do it). I'm still a bit stumped on this if you come up with any other ideas.

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Variable Arugment Macros
« Reply #3 on: June 06, 2006, 11:31:39 AM »
This seems to work to me
Code: [Select]
#define OCALL(a,b,c,...) a->b ( a, ##c, __VA_ARGS__ )
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

Synfire

  • Guest
Variable Arugment Macros
« Reply #4 on: June 07, 2006, 03:21:28 AM »
Well, the version I'm using right now, that sorta works, is:

Code: [Select]
#define OCALL( obj,func,... ) obj->func ( obj, ## __VA_ARGS__ )(new names to make it more readable)

The problem is that it won't work with methods which don't have any arguments. (which is what the ## is supposed to be for). for example, I have an object CFile which has a method called Destroy (which preforms deallocating of heap variables). The only argument required of this method is that of the object itself (ie __VA_ARGS__ is empty). Using the above code, here is what I'm getting for the Destroy method (as well as the Write method just to show it working in a different sence).

Code: [Select]
#define OCALL( obj,func,... ) obj->func ( obj, ## __VA_ARGS__ )
...
// part of the c_file (aka CFile) struct
typedef struct c_file {
 void ( * Write ) ( struct c_file *, char * );
 void ( * Destroy ) ( struct c_file * );
...
void CFile_Write ( CFile *, char * );
void CFile_Destroy ( CFile * );
...
// inside CFile_Create routine for initialization
this->Write = CFile_Write;
this->Destroy = CFile_Destroy;
...
// this code works
OCALL ( fout,Write, buffer );
fout->Write ( fout, buffer );
fout->Destroy ( fout );
...
// this code won't work
OCALL ( fout,Destroy );


Now all the above code works with GCC just fine (with the exception that OCALL is defined with a named vararg like in my first post) This is why when you stated "You missed the ',' (comma) before the variable list designator (...). " I was a bit confused, because in GCC you can name them, I was specifying 'c' as my variable list. I now know that PellesC doesn't use this convention. But the problem now is mearly that (from what I can tell) it always wants to add the comma even when the __VA_ARGS__ list is empty. I'm afraid I'm not making myself clear, and it's totally my fault, I'm horrible at explaining myself (I've been told this many times) I guess I'll just use OCALL() for use with methods which contain arguments, and I'll use the long way for methods which don't contain any.

PS: btw the code you used below doesn't seem to work at all for me. I tried this:

Code: [Select]
#define OCALL( obj,func,arg,... ) obj->func ( obj, ##arg, __VA_ARGS__ )

And I get the following error on every line which contains a call to OCALL:

Code: [Select]
error #1053: Disagreement in number of macro arguments.

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Variable Arugment Macros
« Reply #5 on: June 07, 2006, 09:40:08 PM »
You don't have to worry about explaining yourself (in my opinion means that your brain is quicker then your tongue, and this is good :wink: ), my fault is that I'm a little bit short in time in last weeks so I read very fast and many times miss the point.
Well I analyzed better the issue and I agree with you: doesn't work.
On the other hand I was considering the following points:
- A variable list must accept also an empty list, and this implementation doesn't
- If you put a comma at the end of macro it works putting a comma without any param. I.e.
            #define tst(a,...)  foo(a, __VA_ARGS__)
            .........
            tst(var,)   // -->  foo(var,) ???????????
  And this is clearly wrong!

So I would ask Pelle if he would consider it (bug or feature request?).  :mrgreen:

Thanks Pelle

P.S. for now the only solution is to create two macros one for calls with arguments and another without arguments  :cry:
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

Synfire

  • Guest
Variable Arugment Macros
« Reply #6 on: June 08, 2006, 01:06:40 AM »
Quote
- If you put a comma at the end of macro it works putting a comma without any param. I.e.
#define tst(a,...) foo(a, __VA_ARGS__)
.........
tst(var,) // --> foo(var,) ???????????
And this is clearly wrong!

So I would ask Pelle if he would consider it (bug or feature request?).


That is the purpose of using ##, it adds the comma to the list, if the list empty the comma doesn't get added (in most C compilers). I personally would call it a feature request (I suppose) since it's not used very common and although it is specified in C99, it's part of the extended features list. For now I've just used the long form and ignored the macro, but I would like to have said support as I'm actually playing around with ideas before I undertake a rather large project which I plan to make very modular. The reason I'm not using C++ is I don't really need all the extra "features" (aka bloat) that C++ adds in, and I would much rather use PellesC for this project :)

Offline Pelle

  • Administrator
  • Member
  • *****
  • Posts: 2266
    • http://www.smorgasbordet.com
Variable Arugment Macros
« Reply #7 on: June 08, 2006, 01:32:34 PM »
C99 Rationale:
Quote
There must be at least one argument to match the ellipsis. This requirement avoids the problems that occur when the trailing arguments are included in a list of arguments to another macro or function. For example, if dprintf had been defined as
Code: [Select]
#define dprintf(format, ...) \ 10
dfprintf(stderr, format, _ _VA_ARGS_ _)

and it were allowed for there to be only one argument, then there would be a trailing comma in the expanded form. While some implementations have used various notations or conventions to work around this problem, the Committee felt it better to avoid the problem altogether.
/Pelle