user740006
user740006

Reputation: 1847

Narrowing conversion in C++

In Beej's Guide to Network Programming, there is a function that was meant to provide a portable way to serialize a 16-bit integer.

/*
** packi16() -- store a 16-bit int into a char buffer (like htons())
*/ 
void packi16(unsigned char *buf, unsigned int i)
{
    *buf++ = i>>8; *buf++ = i;
}

I don't understand why the statement *buf++ = i; is portable, as the assignment of an unsigned integer (i) to an unsigned character (*buf) would result in a narrowing conversion.

Upvotes: 1

Views: 1190

Answers (2)

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145279

The code assumes an 8-bit byte, and that is not portable.

E.g. some Texas Instruments digital signal processors have 16-bit byte.

The number of bits per byte is given by CHAR_BIT from <limits.h>.

Also, the code assumes that unsigned is 16 bits, which is not portable.

In summary the code is not portable.


Re

Does the C++ standard guarantees that in such a conversion, the unsigned int is always truncated and its least significant 8 bits are retained in the unsigned char?

No, since the C++ standard does not guarantee that the number of bits per byte is 8.

The only guarantee is that it's at least 8 bits.

Unsigned arithmetic is guaranteed modular, however.


Re

” If not, is there any preferred way to fix the issue?

Use a simple loop, iterating sizeof(unsigned) times.

The code in question appears to have been distilled from such a loop, since the post-increment in *buf++ = i; is totally meaningless (this is the last use of buf).

Upvotes: 3

M.M
M.M

Reputation: 141618

Yes, out-of-range assignments to unsigned types adjust the value modulo one greater than the maximum value representable in the type. In this case, mod UCHAR_MAX+1.

No fix is required. Some people like to write *buf++ = i % 0x100; or equivalent, to make it clear that this was intentional narrowing.

Upvotes: 1

Related Questions