home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c      Meh, in C you gotta define EVERYTHING      243,242 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 241,368 of 243,242   
   Waldek Hebisch to Kaz Kylheku   
   Re: signed vs unsigned and gcc -Wsign-co   
   21 Oct 25 03:52:40   
   
   From: antispam@fricas.org   
      
   Kaz Kylheku <643-408-1753@kylheku.com> wrote:   
   > On 2025-10-21, Keith Thompson  wrote:   
   >> Keith Thompson  writes:   
   >> [...]   
   >>> The thing about unsigned types is that they have a discontinuity at   
   >>> 0, which is much easier to run into than signed int's discontinuties   
   >>> at INT_MIN and INT_MAX.  Subtraction in particular can easily yield   
   >>> mathematically incorrect results for unsigned types (unless your   
   >>> problem domain actuall calls for modular arithmetic).   
   >>   
   >> One specific footgun enabled by unsigned types involves loops that count   
   >> down to zero.  This :   
   >>   
   >>     for (int i = N; i >= 0; i --) {   
   >>         // ...   
   >>     }   
   >>   
   >> is well behaved, but this :   
   >>   
   >>     for (size_t i = N; i >= 0; i --) {   
   >>         // ...   
   >>     }   
   >   
   >   
   > We just have to translate the signed "i >= 0" into unsigned.   
   >   
   > One way is to just directly translate the two's complement semantics   
   > is doing, pretending that the high bit of the value is a sign bit:   
   >   
   >   // if the two's-complement-like "sign bit" is zero ...   
   >   
   >   (SIZE_MAX & (SIZE_MAX >> 1) & i) == 0   
   >   
   > In a downard counting loop, we can just stop when we wrap around   
   > to the highest value, so we get to use most of the range:   
   >   
   >   for (size_t i = N; i != SIZE_MAX; --i) // or (size_t) -1   
   >   
   > (Note: I like to write --i when it's downward, just as a style; it   
   > comes from stacks:  stack[i++] = push; pop = stack[--i].)   
   >   
   > The troublesome case is when N needs to start at SIZE_MAX!   
   >   
   > But that troublesome case exists when counting upward also,   
   > signed or unsigned.   
   >   
   > Signed:   
   >   
   >    // We must break the loop before undefined i++:   
   >   
   >    for (int i = 0; i <= INT_MAX; i++)   
   >   
   >    // Need a bottom-loop break on SIZE_MAX or else infinite loop:   
   >   
   >    for (size_t i = 0; i <= SIZE_MAX; i++)   
   >   
   > This is where BartC will chime in with how languages benefit from   
   > built-in idioms for ranged loops that solve these problems under the   
   > hood. It's a valid argument.   
      
   If you have variable upper and lower bounds which may cover the   
   whole range of the type, than AFAIK on normal machine architecture   
   there is significant loss of efficiency.  C gives you loops   
   which are always efficient, but do not cover corner cases.   
   Other languages may give you low efficiency in cases where programmer   
   thinks that loop is optimal.   Now, most of the time it is   
   better to aim at nicer sematics, possibly making code less   
   efficient.  But C was born to allow "hand optimization", that   
   is writing efficient programs even if this means that programmer   
   must be more careful and spend more work writing a program.  I think   
   that this is still important feature of C.   
      
   --   
                                 Waldek Hebisch   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca