Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > basic help with counting?

Reply
Thread Tools

basic help with counting?

 
 
Ark
Guest
Posts: n/a
 
      11-19-2011
Hello NG,
I want a macro to count the number of tokens in a comma-separated list.
I want it to yield a constant integer expression.

I do something like
#define VERBATIM(...) __VA_ARGS__ //not quite verbatim but OK
#define COUNT(...) \
VERBATIM(sizeof(struct {char VERBATIM(__VA_ARGS__);}))
#define COUNT1(...) \
offsetof(VERBATIM(struct {char VERBATIM(__VA_ARGS__), endmark;}), endmark)

[Of course, VERBATIM is used to package multi-token argument as one
macro parameter.]

The evaluation compiles fine:
const int x = COUNT(a, b, c);

However the conditional fails:
#if COUNT(a, b, c) != 3
....

Here are IAR EWARM 5.30 errors
Error[Pe193]: zero used for undefined preprocessing identifier count.c 13
Error[Pe059]: function call is not allowed in a constant expression
count.c 13
Error[Pe193]: zero used for undefined preprocessing identifier count.c 13
Error[Pe018]: expected a ")" count.c 13

And even more errors with
#if COUNT1(a, b, c) != 3
....

IOW, neither COUNT nor COUNT1 yield a constant integer expression wanted
by #if. Compiler diagnostic is less than helpful.
What am I doing wrong?

Another question:
Is there a trick to make COUNT() and/or COUNT1() yield 0?

--
Thanks - Ark

 
Reply With Quote
 
 
 
 
Kaz Kylheku
Guest
Posts: n/a
 
      11-20-2011
On 2011-11-19, Ark <(E-Mail Removed)> wrote:
> However the conditional fails:
> #if COUNT(a, b, c) != 3


The preprocessing stages in C (a.k.a. "the preprocessor") do not know
anything about types.

Stuff like:

#if sizeof (struct foo) != 3

is impossible. Preprocessor expressions are just integer math, e.g:

#if PROGRAM_VERSION > 3

If PROGRAM_VERSION is not defined, it is replaced with 0.
 
Reply With Quote
 
 
 
 
Ben Bacarisse
Guest
Posts: n/a
 
      11-20-2011
Ark <(E-Mail Removed)> writes:
<snip>
> I want a macro to count the number of tokens in a comma-separated
> list. I want it to yield a constant integer expression.
>
> I do something like
> #define VERBATIM(...) __VA_ARGS__ //not quite verbatim but OK
> #define COUNT(...) \
> VERBATIM(sizeof(struct {char VERBATIM(__VA_ARGS__);}))
> #define COUNT1(...) \
> offsetof(VERBATIM(struct {char VERBATIM(__VA_ARGS__), endmark;}), endmark)
>
> [Of course, VERBATIM is used to package multi-token argument as one
> macro parameter.]
>
> The evaluation compiles fine:
> const int x = COUNT(a, b, c);
>
> However the conditional fails:
> #if COUNT(a, b, c) != 3
> ...

<snip>
> And even more errors with
> #if COUNT1(a, b, c) != 3
> ...
>
> IOW, neither COUNT nor COUNT1 yield a constant integer expression
> wanted by #if. Compiler diagnostic is less than helpful.
> What am I doing wrong?


C is defined in terms of a number of translation phases (eight in all).
Most deal with lexical matters (continuation lines, comments, finding
tokens, and so on). Preprocessing happens in phase 4 -- long before the
main work of translating the code that happens in phase 7.

Because of this, there is a special definition for constant expressions
used in #if directives. The main difference is that all identifiers
that are left over after macro expansion are replaced with 0. This
applies even to identifiers that would otherwise be keywords. struct,
char and sizeof are all simply replaced by 0 when your macros are used
after #if.

> Another question:
> Is there a trick to make COUNT() and/or COUNT1() yield 0?


Sorry, but I can't answer this. There probably is a way -- there is an
honourable tradition of amazing macro trickery -- but, from a purely
practical point of view, it is often better to use some other
preprocessor. This can limit portability, but it's often the way the go
to get the job done.

--
Ben.
 
Reply With Quote
 
Stefan Ram
Guest
Posts: n/a
 
      11-20-2011
Ark <(E-Mail Removed)> writes:
>#if COUNT(a, b, c) != 3


#define COUNT(...) SELECT_POSITION_4_OF(__VA_ARGS__,LIST43210())
#define SELECT_POSITION_4_OF(...) SELECT_POSITION_4(__VA_ARGS__)
#define SELECT_POSITION_4(dummy0,dummy1,dummy2,dummy3,x,.. .) x
#define LIST43210() 4,3,2,1,0

#if COUNT(A)!=1
#error
#endif

#if COUNT(A,B)!=2
#error
#endif

#if COUNT(A,B,C)!=3
#error
#endif

 
Reply With Quote
 
Ark
Guest
Posts: n/a
 
      11-20-2011


On 11/19/2011 8:50 PM, Stefan Ram wrote:
> Ark<(E-Mail Removed)> writes:
>> #if COUNT(a, b, c) != 3

>
> #define COUNT(...) SELECT_POSITION_4_OF(__VA_ARGS__,LIST43210())
> #define SELECT_POSITION_4_OF(...) SELECT_POSITION_4(__VA_ARGS__)
> #define SELECT_POSITION_4(dummy0,dummy1,dummy2,dummy3,x,.. .) x
> #define LIST43210() 4,3,2,1,0
>
> #if COUNT(A)!=1
> #error
> #endif
>
> #if COUNT(A,B)!=2
> #error
> #endif
>
> #if COUNT(A,B,C)!=3
> #error
> #endif
>

That's truly excellent! Thank you very much!
(Unfortunately, COUNT() is still a 1, not 0.)
--
Ark
 
Reply With Quote
 
Ark
Guest
Posts: n/a
 
      11-20-2011


On 11/19/2011 8:37 PM, Ben Bacarisse wrote:
> Ark<(E-Mail Removed)> writes:
> <snip>
>> I want a macro to count the number of tokens in a comma-separated
>> list. I want it to yield a constant integer expression.
>>
>> I do something like
>> #define VERBATIM(...) __VA_ARGS__ //not quite verbatim but OK
>> #define COUNT(...) \
>> VERBATIM(sizeof(struct {char VERBATIM(__VA_ARGS__);}))
>> #define COUNT1(...) \
>> offsetof(VERBATIM(struct {char VERBATIM(__VA_ARGS__), endmark;}), endmark)
>>
>> [Of course, VERBATIM is used to package multi-token argument as one
>> macro parameter.]
>>
>> The evaluation compiles fine:
>> const int x = COUNT(a, b, c);
>>
>> However the conditional fails:
>> #if COUNT(a, b, c) != 3
>> ...

> <snip>
>> And even more errors with
>> #if COUNT1(a, b, c) != 3
>> ...
>>
>> IOW, neither COUNT nor COUNT1 yield a constant integer expression
>> wanted by #if. Compiler diagnostic is less than helpful.
>> What am I doing wrong?

>
> C is defined in terms of a number of translation phases (eight in all).
> Most deal with lexical matters (continuation lines, comments, finding
> tokens, and so on). Preprocessing happens in phase 4 -- long before the
> main work of translating the code that happens in phase 7.
>
> Because of this, there is a special definition for constant expressions
> used in #if directives. The main difference is that all identifiers
> that are left over after macro expansion are replaced with 0. This
> applies even to identifiers that would otherwise be keywords. struct,
> char and sizeof are all simply replaced by 0 when your macros are used
> after #if.


Sure. My bad; I should have known better.

>
>> Another question:
>> Is there a trick to make COUNT() and/or COUNT1() yield 0?

>
> Sorry, but I can't answer this. There probably is a way -- there is an
> honourable tradition of amazing macro trickery -- but, from a purely
> practical point of view, it is often better to use some other
> preprocessor. This can limit portability, but it's often the way the go
> to get the job done.
>


I know I even wrote my own preprocessor (Unimal) but the team I am on
is willing to use it only when no C native alternative is available.

--
Ark
 
Reply With Quote
 
Ark
Guest
Posts: n/a
 
      11-20-2011


On 11/19/2011 8:13 PM, Kaz Kylheku wrote:
> On 2011-11-19, Ark<(E-Mail Removed)> wrote:
>> However the conditional fails:
>> #if COUNT(a, b, c) != 3

>
> The preprocessing stages in C (a.k.a. "the preprocessor") do not know
> anything about types.
>
> Stuff like:
>
> #if sizeof (struct foo) != 3
>
> is impossible. Preprocessor expressions are just integer math, e.g:
>
> #if PROGRAM_VERSION> 3
>
> If PROGRAM_VERSION is not defined, it is replaced with 0.

Thanks, got it.
 
Reply With Quote
 
Joel C. Salomon
Guest
Posts: n/a
 
      11-20-2011
On 11/19/2011 05:44 PM, Ark wrote:
> I want a macro to count the number of tokens in a comma-separated list.
> I want it to yield a constant integer expression.


Almost six years ago, Laurent Deniau posted PP_NARG to comp.std.c; see
<https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s>.

More recently, Jens Gustedt posted an enhancement that will correctly
count the zero-arguments case; see
<http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/> &
<http://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/>.

--Joel
 
Reply With Quote
 
Phil Carmody
Guest
Posts: n/a
 
      11-21-2011
"Joel C. Salomon" <(E-Mail Removed)> writes:

> On 11/19/2011 05:44 PM, Ark wrote:
> > I want a macro to count the number of tokens in a comma-separated list.
> > I want it to yield a constant integer expression.

>
> Almost six years ago, Laurent Deniau posted PP_NARG to comp.std.c; see
> <https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s>.
>
> More recently, Jens Gustedt posted an enhancement that will correctly
> count the zero-arguments case; see
> <http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/> &


All very clever, but I'm not sure I see why 9 lines of NOISE is better
than just

static inline int one_or_two_lazy(int a) { return one_or_two(a, 5); }

Or, horror of horrors, simply provividing the default parameter. Missing
it out is purely syntactic sugar, nothing more.

Phil
--
Unix is simple. It just takes a genius to understand its simplicity
-- Dennis Ritchie (1941-2011), Unix Co-Creator
 
Reply With Quote
 
Ark
Guest
Posts: n/a
 
      11-21-2011


On 11/20/2011 3:54 PM, Joel C. Salomon wrote:
> On 11/19/2011 05:44 PM, Ark wrote:
>> I want a macro to count the number of tokens in a comma-separated list.
>> I want it to yield a constant integer expression.

>
> Almost six years ago, Laurent Deniau posted PP_NARG to comp.std.c; see
> <https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s>.
>
> More recently, Jens Gustedt posted an enhancement that will correctly
> count the zero-arguments case; see
> <http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/> &
> <http://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/>.
>
> --Joel

Thanks, Joel, very interesting.
But seems too academic all the same.
From the cost/benefit analysis, it's hard to justify the maintenance
overhead (+bugs, whether in macros or in compilers) of having COUNT()
expand to 0.
If I wanted it VERY badly, I'd go with external preprocessor. For now,
I'll live with COUNT() expand to 1. It's a simplified version, also
proposed by Stefan.
-- Ark
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
TurboTax Basic vs. Taxcut Basic? Sharp Dressed Man Computer Support 1 01-12-2009 12:52 PM
What is the difference between Visual Basic.NET and Visual Basic 6? Jimmy Dean Computer Support 3 07-25-2005 07:05 AM
Re: Python interpreter in Basic or a Python-2-Basic translator. rrr@ronadam.com Python 0 05-02-2005 01:48 PM
Python interpreter in Basic or a Python-2-Basic translator. Engineer Python 6 05-01-2005 10:16 PM
Upgrading Microsoft Visual Basic 6.0 to Microsoft Visual Basic .NET Jaime MCSD 2 09-20-2003 05:16 AM



Advertisments