pete:

Whether or not you can set an unsigned char to 65000

is implementation defined,

so there's nothing wrong

with an implementation defined way of doing it.

The reason I mentioned concrete figures like 65535 instead of

UCHAR_MAX is that I think people find it easier to understand and

grasp.

The point wasn't whether we could assign 65000 to an int, but rather

whether we could assign (UCHAR_MAX - some_small_number) to an int and

have the same results on every implementation conceivable.

For clarity, I'll rewrite my original post taking out the concrete

numbers. Remember again, that the code is being written in the context

of it being FULLY portable (e.g. 97-Bit char's and sign-magnitude):

Let's say we have an array of bytes and we want to set every byte to

(UCHAR_MAX - 4). We CANNOT use:

memset(data, UCHAR_MAX - 4, sizeof data);

because the conversion from unsigned integer types to signed integer

types "is implementation-defined or an implementation-defined signal

is raised" if the number is out of range. (So in the context of fully

portable programming, the resultant int could have pretty much any

value because UCHAR_MAX might be bigger than INT_MAX).

Therefore we need to supply memset with an int value, which, went

converted to unsigned char, will yield the value we want.

The rules for converting from signed to unsigned are as follows:

| If the new type is unsigned, the value is converted

| by repeatedly adding or subtracting one more than

| the maximum value that can be represented in the

| new type until the value is in the range of the new type.

The addition method is easier to understand so we'll go with that

one.

If we start off with a negative number like -1, then here's what will

happen:

char unsigned c = -1;

is equal to:

infinite_range_int x = -1; /* Let's pretend we have a signed

int type that can hold any number */

while (0 x || UCHAR_MAX < x) x += UCHAR_MAX +

(infinite_range_int)1;

char unsigned c = x;

So here's a few samples of what will happen on different systems:

while (0 x || 255 < x) x += 256;

while (0 x || 65535 < x) x += 65536;

while (0 x || 4294967295 < x) x += 4294967296;

while (0 x || 18446744073709551615 < x) x +=

18446744073709551616;

If x = -1, then it only takes one iteration of the loop to

yield UCHAR_MAX on any implementation.

Therefore, if we want UCHAR_MAX-1, then we'd use (int)-2.

For UCHAR_MAX-2, we'd use (int)-3.

The entire set of data looks something like:

int char unsigned

-1 UCHAR_MAX

-2 UCHAR_MAX-1

-3 UCHAR_MAX-2

-4 UCHAR_MAX-3

-5 UCHAR_MAX-4

-6 UCHAR_MAX-5

-7 UCHAR_MAX-6

-8 UCHAR_MAX-7

-9 UCHAR_MAX-8

-10 UCHAR_MAX-9

-11 UCHAR_MAX-10

-12 UCHAR_MAX-11

....

....

Now I've just realised a problem. Imagine a system where unsigned char

has the range 0 through 65535 and where int has -32767 through 32767.

The former has 65536 possible combinations while the latter only has

65535 combinations. We might have to resort to a loop if working with

something other than two's complement, but I'm not sure yet.

Anyway here's the code I have at the moment, I robbed some of it from

old posts of yours pete:

#define SIGNMAG 0

#define ONES 1

#define TWOS 2

#if -1 & 3 == 1

#define NUM_SYS SIGNMAG

#elif -1 & 3 == 2

#define NUM_SYS ONES

#else

#define NUM_SYS TWOS

#endif

#if NUM_SYS != TWOS /* ----------- */

#include <stddef.h>

static void *uc_memset(void *const pv,char unsigned const val,size_t

const len)

{

char *p = pv;

char const *const pover = p + len;

while (pover != p) *p++ = val;

return pv;

}

#define UC_MEMSET(p,uc,len) (uc_memset(p,uc,len))

#else /* ------------ */

#include <string.h>

#define UC_AS_INT(x) UC_AS_INT_Internal( (char unsigned)(x) )

#define UC_AS_INT_Internal(x) ( x INT_MAX \

? -(int)(UCHAR_MAX - x) - 1 \

: (int)x )

#define UC_MEMSET(p,uc,len) (memset((p),UC_AS_INT((uc)),(len)))

#endif /* ----------- */

#include <limits.h>

int main(void)

{

char unsigned data[24];

UC_MEMSET(data, UCHAR_MAX, sizeof data);

return 0;

}

Feel free to make alterations if you see a better way of doing it!

Martin