Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: How to add ssize_t a by size_t b? Date: Sat, 02 Oct 2021 15:13:41 -0700 Organization: A noiseless patient Spider Lines: 61 Message-ID: <864k9zrs6i.fsf@linuxsc.com> References: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="1a64f0de92465f6d033f50ce67cc535c"; logging-data="26763"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19UflWYFI5h8XAjF+B/I++n/eJVaYrk3ig=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:HB5MI/0QOzGRFlXtdJultFX/A/Q= sha1:00GmiS2cDoAAhwH0BUnRdCfTA2E= Xref: csiph.com comp.lang.c:162948 James Kuyper writes: > On 10/1/21 1:39 PM, Guillaume wrote: > >> Le 01/10/2021 at 17:32, wij a ecrit: >> >>> To simply the question of "a+b": >>> >>> ssize_t add(ssize_t a, size_t b) { >>> if(a+b would overflow) { set errno=ERANGE; } >>> a+=b; // ? >>> return a; >>> } >>> >>> Another example: >>> ssize_t a=SSIZE_T_MIN; >>> size_t b=SIZE_T_MAX; >>> a+=b; // Is this OK? Or, How the addition is done correctly? >> >> ssize_t is not standard C. It's defined in POSIX. >> While it's a signed integer, whereas size_t is unsigned, I don't know >> how it relates to size_t on a given implementation in terms of width. > > ssize_t is a signed integer type with the same width as size_t. I don't see anything on the pubs.opengroup.org website that requires that. > Therefore, they should have the same integer conversion rank. Since > the sign bit is included in the width, SSIZE_MAX is guaranteed to be > smaller than SIZE_MAX. > > The usual arithmetic conversions apply (6.5.6p5). The ssize_t value > is first converted to size_t (6.3.1.8p1). That is a well-defined > conversion - negative ssize_t values have SIZE_MAX+1 added to them > (6.3.1.3p2). The sum is calculated using size_t math, which will > produce what I assume is the desired result even if a is negative, > so long as it is smaller than b. > > Upon assignment, the result is converted to ssize_t. Values greater > than SSIZE_MAX would not result in undefined behavior, as you > suggested. Instead, they would result in an implementation-defined > value or the raising of an implementation-defined signal (6.3.1.3p3). > This code will probably not work as desired on an implementation that > chooses to raise a signal, and the implementation- defined value is > not guaranteed to be the one that he wants. Therefore, setting errno > would not be sufficient, the final conversion must be actively > prevented from occurring if it would otherwise overflow. > > I would write the function as: > > size_t c = a + b; > if(c > SSIZE_MAX) > return overflow_value; > else > return c; > > where overflow_value is whatever value he wants add() to return > when there's an overflow. [...] An exemplary proposal: short, simple, and wrong.