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: for-loop mutates to an endless-loop Date: Sat, 11 Jan 2020 10:01:48 -0800 Organization: A noiseless patient Spider Lines: 98 Message-ID: <86pnfp27oz.fsf@linuxsc.com> References: <87ftgwpqbi.fsf@bsb.me.uk> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="a658bb27d1b88b897660621da5fe7a9e"; logging-data="30932"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/TZ2Q7mLaOyAZDg82eOJOAl0nenVF3qBM=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:kfRYZ7fSA2kDNPBbgXF+3XxxGGM= sha1:nT/0IfY4U4/u1pZJriQlQtHxeTI= Xref: csiph.com comp.lang.c:148939 Ben Bacarisse writes: > "Walter H." writes: > > >> then I tried the same in C with several compilers >> 32-bit, 64-bit Intel, GNU under Linux or Visual C++ under Windows >> even QuickC or Turbo C every one built this programme with an endless-loop; >> >> [code] >> #include >> int main( int argc, char* argv[ ] ) >> { >> short int nIter; > > This may or may not by a 16-bit integer. It probably will be, but > modern C has the type int16_t that you can use to be sure. #include > to get these new known-width types. > >> long lSum = 0; >> for ( nIter = -32768; nIter <= 32767; nIter++ ) > > When you need numbers like this it better to #include and use > SHRT_MIN and SHRT_MAX. If you included stdint.h to use int16_t then > INT16_MIN and INT16_MAX are available. > > Also, in modern C you can declare the loop variable in the for > statement: > > for (short nIter = -32768; nIter <= 32767; nIter++) ... > >> lSum += nIter; >> printf( "sum: %ld\n", lSum ); >> return 0; >> } >> [/code] > > Adding a bit to the answer you already have... > > If nInter is indeed a 16-bit integer type, and int is wider (the most > likely situation here) then the behaviour of the code above is > implementation-defined. > > Once nIter gets to 32767, the increment in the for loop causes a problem > when the result (which will be of type int) is converted back to short. > The result is either an implementation-defined value or an > implementation-defined signal will be raised. > > Anyway, unless a signal is raised, the result is bound to be <= 32767 > so, as has been pointed out, the test is never false. > >> here the same in old FORTRAN which also worked as expected; >> >> [code] >> PROGRAM SumDemo >> INTEGER*2 nIter >> INTEGER*4 lSum >> lSum = 0 >> DO nIter = -32768,32767,1 >> lSum = lSum + nIter >> END DO >> WRITE ( *, * ) 'sum: ', lSum >> END >> [/code] > > Curiously, the GNU Fortran compiler gets this wrong (at least as far as > my understanding of F77 goes) and generates an endless loop. > > > >> what would be the correct way of a for-loop >> with the complete range of an integral type? > > One solution is to use a wider type: > > for (int_fast32_t i = INT16_MIN; i <= INT16_MAX; i++) ... > > but that is not always possible. The general solution is to test at the > end, after the increment: > > short i = SHRT_MIN; > do sum += i; while (i++ < SHRT_MAX); > > but this is not portable to implementations where (a) short is as wide > as int (in which case the increment is undefined behaviour), or (b) > implementations that raise a signal when converting an out-of-range > value to short. > > A portable solution must increment only when i < SHRT_MAX: > > do sum += i; while (i < SHRT_MAX && i++ | 1); Another way to achieve the same effect: do sum += i; while (i < SHRT_MAX && i++ < SHRT_MAX); (It seems likely that optimization will omit the redundant comparison.)