Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c
Subject: Re: Comma operator in for() statements
Date: Thu, 02 Apr 2020 19:43:31 -0700
Organization: A noiseless patient Spider
Lines: 78
Message-ID: <86wo6xnvak.fsf@linuxsc.com>
References: <87zhc72f0u.fsf@bsb.me.uk> <6ed3fe7f-aa6e-41b7-9753-285b616c2cf4@googlegroups.com> <87eetirfyb.fsf@nosuchdomain.example.com> <871rpirdt3.fsf@nosuchdomain.example.com> <5788dcca-ca28-4fb4-b454-89436c601d0c@googlegroups.com> <87wo7aps7r.fsf@nosuchdomain.example.com> <87y2rq0zmy.fsf@bsb.me.uk> <27ca29d7-392f-443a-be90-097ed390a674@googlegroups.com> <864ku9ap29.fsf@linuxsc.com> <1e31345c-84a7-4dcd-b0a4-8024bf91acbf@googlegroups.com> <87blogwwi6.fsf@bsb.me.uk> <3d13c9c6-5788-4f7b-ae9a-10f36aa07a19@googlegroups.com> <86wo6x6hwa.fsf@linuxsc.com> <91a4ce3a-e744-4fd9-87c3-ca6f50d7ac89@googlegroups.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: reader02.eternal-september.org; posting-host="764a289b4fffae23755ccdbd2c0254f8"; logging-data="28292"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18j++0G8NPiDYbRgWw5722wgjCWNMK7EsE="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:K82Wh9VRxILNkxcDulcmDxwt/ac= sha1:hvxDaDqjcSgNbBt2japurn8sg9Y=
Xref: csiph.com comp.lang.c:150970
luser droog writes:
> On Thursday, April 2, 2020 at 10:12:47 AM UTC-5, Tim Rentsch wrote:
>
>> luser droog writes:
>>
>>> //#include
>>>
>>> #define UNIQUE(x) UNIQUE_(PASTE(x, _), __LINE__)
>>> #define UNIQUE_(x, line) PASTE(x, line)
>>> #define PASTE(t1, t2) t1 ## t2
>>>
>>> #define P_FOR( TYPE, IDX, INI, TEST, INC ) \
>>> for( TYPE UNIQUE(IDX) = (INI); UNIQUE(IDX) TEST; UNIQUE(IDX) INC ) \
>>> for( int once = 1; once; ) \
>>> for( TYPE const IDX = UNIQUE(IDX); once; once = 0 )
>>
>> Good work. A few suggestions for you -
>>
>> * Give 'UNIQUE(IDX)' as an argument to a subsidiary macro call, so
>> the value is determined in only one place. Besides liking the
>> definition being more factored, I don't want to rely on __LINE__
>> being the same when the macro is invoked from different physical
>> source lines.
>>
>> * The variable 'once' is probably better as UNIQUE( IDX ## _once ).
>>
>> * See if you can write a solution that uses only two for()'s
>> instead of three.
>
> It took me a good while to understand the first suggestion, but now
> that I have, yes, it's so much nicer with the extra macro.
>
> //#include
>
> #define UNIQUE(x) UNIQUE_(PASTE(x, _), __LINE__)
> #define UNIQUE_(x, line) PASTE(x, line)
> #define PASTE(t1, t2) t1 ## t2
>
> #define M_FOR( type, idx, ini, test, inc, iter, once ) \
> for( type iter = ini, once = 1; iter test; iter inc ) \
> for( type const idx = iter; once; once = 0 )
>
> #define P_FOR( type, idx, ini, test, inc ) \
> M_FOR( type, idx, ini, test, inc, UNIQUE(idx), UNIQUE(idx ## _once ) )
This way doesn't quite work - the inner loop is run only for
the first iteration of the outer loop. You need to be a bit
more clever with the once initialization.
> [...]
> struct list {
> int value;
> struct list *next;
> } *head = 0;
>
> //P_FOR( struct list *, node, head, , =node->next ) sum += node->value;
>
> printf("%d\n", sum );
> }
> I can't see an easy way to make it work with a linked list or
> other uses of a for loop. One problem is the pointerness gets
> lost after the comma in the declarator, so the 'once' variable
> is trying to be a struct object. The compiler said it wants
> a scalar value there.
Good point. From this perspective three for() statements is
more flexible than two for() statements.
> Second, in the increment expression,
> the iterator variable is not available by name. So there's no
> way to make the "=node->next" expression.
One way would be for the argument for 'inc' be a macro name, and
have the expansion call 'inc( iter )'. A small number of
pre-defined macros would suffice to handle the common cases,
while still giving a way of covering unusual cases not yet
thought of.