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.