Question

Here is a short snippet of a function reading lines. How is that possible that it compares bufsize with ((size_t)-1)/2 ?

I imagined comparing a variable to eg. int - that is just impossible; to INT_MAX on the contrary it is correct, I think. So how can that code actually work and give no errors?

int c;
size_t bufsize = 0;
size_t size = 0;

while((c=fgetc(infile)) != EOF) {
    if (size >= bufsize) {
        if (bufsize == 0)
                bufsize = 2;
        else if (bufsize <= ((size_t)-1)/2)
                bufsize = 2*size;
        else {
                free(line);
                exit(3);
        }
        newbuf = realloc(line,bufsize);
        if (!newbuf) {
                free(line);
                abort();
        }
        line = newbuf;
    }
    /* some other operations */
}
Was it helpful?

Solution

The code relies on some assumptions about bits and then does a well known hack for finding the maximum size_t value (provided that size_t doesn't accommodate more bits than the register, a safe bet on many machines).

First it fills a register up with 1 bits, then it casts it into a size_t data type, so the comparison will work. As long as that register is larger in number of bits than the size_t data type, then the (if any) unused 1 bits will be truncated, and you will get the largest unsigned number that can fit in size_t bits.

After you have that, it divides by two to get half of that number, and does the comparison to see if it seems to be safe to increase size without going over the "maximum" size_t. but by then, it's dividing a size_t data type, and comparing two size_t data types (a type safe operation).

If you really wanted to remove this bit-wizardy (ok, it's not the worst example of bit wizardy I've seen). Consider that the following snippet

    else if (bufsize <= ((size_t)-1)/2)
            bufsize = 2*size;

could be replaced with

    else if (bufsize <= (MAX_SIZE/2)
            bufsize = 2*size;

and be type safe without casting and more readable.

OTHER TIPS

(size_t)-1

This is casting the value -1 to a size_t. (type)value is a cast in C.

Since size_t is an unsigned type, this is actually the maximum value that size_t can hold, so it's used to make sure that the buffer size can actually be safely doubled (hence the subsequent division by two).

(size_t)-1 casts -1 to the type size_t, which results in SIZE_MAX (a macro defined in stdint.h), the maximum value that the size_t type can hold.

So the comparison is checking whether bufsize is less than or equal to one half the maximum value that can be contained in a size_t

size_t isn't being interpreted as a value, it's being used to cast the value of negative one to the type size_t.

((size_t)-1)/2

is casting -1 to a size_t and then dividing by 2.

The size_t in ((size_t)-1)/2) is simply being used as a cast: casting -1 to size_t.

The trick here is that size_t is unsigned, so the cast (size_t) -1 will be converted to the maximum value of size_t, or SIZE_MAX. This is useful in the context of the loop. However, I'd prefer to see SIZE_MAX used directly rather than this trick.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top