Re: A portability poser: adding two unsigned shorts



Mark Dickinson wrote:
Here's a simple, largely theoretical puzzle about portability and
standards compliance. I don't know of any existing implementations
where the problem described below could ever come up.

Suppose I want to write portable C99 code for a function that adds two
unsigned shorts x and y, and returns their sum modulo USHRT_MAX+1. On
the face of it, this seems trivial:

unsigned short add_ushorts(unsigned short x, unsigned short y) {
return x+y;
}

should do it. But I've just managed to convince myself that this code
isn't portable, and could even invoke undefined behaviour on some
platforms! And now I'm shocked and horrified, and would dearly like
someone to tell me that I'm misunderstanding.

The problem occurs if the width of int is exactly 1 larger than the
width of unsigned short (or equivalently, the precision of int is
equal to that of unsigned short). Then int is large enough (but only
just) to hold all unsigned short values, so according to C99 6.3.1.1
paragraph 2, both x and y are converted to int before the addition.
But because int is only just big enough to hold x and y, the sum x+y
could overflow, so the above function has the potential to invoke
undefined behaviour.

Question 1: Is this analysis correct, or am I missing something?

It's correct, as far as I can see. Note that "int is one bit
wider than unsigned short" implies padding bits in one or both of
the types (otherwise, they'd have to differ by a multiple of CHAR_BIT
bits).

Question 2: The above problem (if it is a problem) is easily fixed by
explicitly casting x and y to unsigned int before the addition. But
in the actual code I'm looking at, I don't have unsigned short, but
instead I have a type 'digit', which is a typedef for some unsigned
integer type of unknown rank. So I want:

digit add_digits(digit x, digit y) {
return x+y;
}

except that this still has the same portability problem as above.
What's the best way to write this so that it's fully
standards-compliant and portable, and will do the correct thing
(addition modulo one more than the largest value representable as a
digit) for any unsigned integer type 'digit'.

The problem can only occur if digit has a lesser rank than int;
anything with greater rank is unchanged by the integer promotions.
Also, any unsigned type of rank not exceeding int can convert safely
to unsigned int. Putting these together and trusting your compiler
to eliminate dead code leads to

digit add_digits(digit x, digit y) {
if ((digit)-1 <= (unsigned int)-1)
return (unsigned int)x + (unsigned int)y;
else
return x + y;
}

Aside: Did I hear rumors of a TC to C99 that forbade padding bits
in integer types? Or was I just dreaming a dream of the Blissful Realm?

--
Eric.Sosman@xxxxxxx
.



Relevant Pages

  • Re: How do you decide which integer type to use? (bitmasking question)
    ... >> Any C integer type can represent ASCII characters without a problem ... Not sure of the syntax but if an int as 4 bits, ... about portability and you only want to run the program on your particular ... For example on my Pentium based PC using the Borland compiler I might do ...
    (comp.lang.c)
  • A portability poser: adding two unsigned shorts
    ... standards compliance. ... The problem occurs if the width of int is exactly 1 larger than the ... instead I have a type 'digit', which is a typedef for some unsigned ... except that this still has the same portability problem as above. ...
    (comp.lang.c)
  • Re: A portability poser: adding two unsigned shorts
    ... The problem occurs if the width of int is exactly 1 larger than the ... instead I have a type 'digit', which is a typedef for some unsigned ... except that this still has the same portability problem as above. ... conversion. ...
    (comp.lang.c)
  • Re: Bit-fields and integral promotion
    ... >> The standard very clearly intends to specify the behaviour. ... > whether declared as int or unsigned int, ... "A bit-field is interpreted as a signed or unsigned integer type ... any signed integer type with less precision." ...
    (comp.lang.c)
  • Re: Moving from C++ to VC++
    ... If it is the longest integer. ... have been bad to constrain fseek to 16 bit int offsets, so they used long, ... 8192 bit integer type is a very special type that is mind-boggling overkill ... Storing pointers in an integer is common enough that the C++ Standard ...
    (microsoft.public.vc.language)